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.

Revisions

  1. RadGH revised this gist May 16, 2022. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -127,7 +127,11 @@ public function get_edited_entry_id() {
    $entry_id = (int) rgar( $_GET, $this->query_arg );
    if ( !$entry_id ) $entry_id = false;

    return $entry_id;
    if ( $this->can_user_edit_entry( get_current_user_id(), $entry_id ) ) {
    return $entry_id;
    }else{
    return false;
    }
    }

    /**
  2. RadGH revised this gist May 16, 2022. 1 changed file with 323 additions and 130 deletions.
    453 changes: 323 additions & 130 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -1,86 +1,330 @@
    <?php
    if ( !defined( 'ABSPATH' ) ) exit;
    /*
    Plugin Name: GF Editable by Radley
    Description: Example classes to make a particular gravity form editable on the front-end.
    Author: Radley Sustaire
    Author URI: https://radleysustaire.com/
    Version: 1.0.0
    */

    // How to use:
    // 1. Create your own class that extends this one, such as: class Amazing_Quiz extends Editable_GF_Form {...}
    // 2. Set the $form_id in your class (Amazing_Quiz). *Note: This code is designed for a single form per class but could easily be adapted to support any form.
    // 3. Edit an entry by visiting your form normally but with ?entry_id=123 in the URL. If your user account created the entry, you can edit it.
    // QUICK TEST INSTRUCTIONS:
    // 1. Import this example form in Gravity Forms (download as json):
    // https://gist.github.com/RadGH/afb032d642515aedbb068f6b5990b668
    //
    // 2. Modify "GF_Form_12" below to be your own form ID after import.
    // * If you change the class, make sure to replace "new GF_Form_12()" below too.
    //
    // 3. Submit an entry on the form.
    // 4. Go back to the form and add ?edited_entry_id=100 (where 100 is your entry id)
    // 5. Field values should populate, allowing to edit the same entry.

    // Requirements:
    // 1. All fields must have a unique name set for "allow to be pre-populated".
    // * This is a dumb restriction by GF as without a name, there is no filter to set the value.
    // * File inputs do not need a name though (they don't support one anyway).
    // 3. This is only for the front-end. I don't know why GF doesn't let you edit entries on the backend.


    // RECOMMENDED AFTER TESTING:
    //
    // 1. Put the "abstract" class Editable_GF_Form into a separate file.
    // 2. Create a copy of GF_Form_12 for any of your forms.
    // 3. Include the abstract class, and your custom classes, then instantiate your custom classes like: new GF_Form_12()




    // Extending "Editable_GF_Form" gives the ability to edit entries. You only need to supply $form_id and $query_arg

    /**
    * @class GF_Form_12
    * @version 1.0
    */
    class GF_Form_12 extends Editable_GF_Form {

    // Each form should have its own class.
    public $form_id = 12;

    public $query_arg = 'edited_entry_id';

    public function __construct() {
    // Add essential hooks from the parent Editable_GF_Form class
    parent::__construct();

    // Register actions or filters for the form here.

    // EXAMPLE: Add a key when the form gets saved
    // add_filter( 'gform_entry_post_save', array($this, 'fill_random_key'), 30, 2 );

    }

    // EXAMPLE: The function to add a key when the form gets saved
    /*
    public function fill_random_key( $entry, $form ) {
    if ( $this->form_id != $form['id'] ) return $entry;
    // Some form of key
    $key = uniqid();
    // Save to the database
    gform_update_meta( $entry['id'], 'secret_key', $key );
    // Add to current entry too
    $entry['secret_key'] = $key;
    return $entry;
    }
    */

    }

    // Remember to instantiate your class, or else it won't do anything.
    new GF_Form_12();





    /**
    * This class is used to make a gravity form entry editable.
    * Do not edit below, create your own object that extends this class.
    * An example is above "GF_Form_12"
    */
    abstract class Editable_GF_Form {

    // Form ID that will allow editing entries
    /**
    * Form ID that will allow editing entries.
    *
    * @var int
    */
    public $form_id = null;
    public $initialized = false;
    public $sub_inputs = array();

    public function __construct() {;
    // Add other hooks on every page load -- for things like saving data
    add_action( 'after_setup_theme', array( $this, 'add_hooks_on_every_load' ) );
    // Internal variables
    protected $uploads = array();
    protected $sub_inputs = array();

    public function __construct() {
    if ( $this->form_id === null ) {
    _doing_it_wrong(__FUNCTION__, '$this->form_id must be an integer', '1.0');
    exit;
    }

    // When editing an entry, change the entry ID to the edited entry instead of creating a new entry
    add_filter( "gform_entry_id_pre_save_lead_{$this->form_id}", array($this, 'change_saved_entry_id'), 50, 2 );

    // Prepare the form to be editable on a very early hook
    add_filter( 'gform_form_args', array( $this, 'prepare_editable_form' ), 20 );

    // Insert field values for most fields
    add_filter( "gform_field_value", array($this, 'load_regular_field_value'), 20, 3 );

    // Keeps file uploads unless the user actually deletes or replaces them
    add_filter( "gform_pre_process", array( $this, 'pre_restore_existing_uploads' ), 20, 1 );

    // Add certain hooks only when the form is going to be displayed (based on shortcode usage)
    add_filter( 'gform_form_args', array( $this, 'add_hooks_on_display' ), 20 );
    }

    /**
    * Add hooks so that entry can save. This can happen on submit or ajax, the shortcode will not be processed so it needs a separate hook.
    * Get the entry id that is being edited from the url ?entry_id=100
    *
    * @return int|false
    */
    public function add_hooks_on_every_load() {
    // Only for this form
    if ( $this->form_id === null ) return;
    public function get_edited_entry_id() {
    $entry_id = (int) rgar( $_GET, $this->query_arg );
    if ( !$entry_id ) $entry_id = false;

    // 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, 'change_saved_entry_id'), 50, 2 );
    return $entry_id;
    }

    /**
    * Keeps file uploads unless the user actually deletes or replaces them.
    * Gravity forms seems to do this, but fails at it.
    * To make this work we capture values before (here) and restore them after the entry is saved.
    *
    * @param $form
    *
    * @return mixed
    */
    public function pre_restore_existing_uploads( $form ) {
    if ( $form['id'] != $this->form_id ) return $form;

    $entry_id = $this->get_edited_entry_id();

    // Get uploads from $_POST, served as JSON string, which has file upload info
    $uploads = rgpost( 'gform_uploaded_files' );
    if ( !$uploads ) return $form;

    // Decode the json
    $uploads = json_decode( $uploads );

    // Each file upload field will have the previous filename, or NULL if removing that file.
    if ( $uploads ) foreach( $uploads as $input_name => $file ) {

    // If file was removed by user, or replaced with new file
    if ( ! $file ) continue;

    // File should be kept.
    $field_id = (int) str_replace('input_', '', $input_name );
    $url = gform_get_meta( $entry_id, $field_id );

    $this->uploads[ $input_name ] = array(
    'entry_id' => $entry_id,
    'input_name' => $input_name,
    'field_id' => $field_id,
    'url' => $url
    );
    }

    add_filter( "gform_after_submission_{$form['id']}", array( $this, 'restore_existing_uploads' ), 10, 2 );

    return $form;
    }

    /**
    * Restore files preserved by pre_restore_existing_uploads() after the entry has been saved
    *
    * @param $entry
    * @param $form
    *
    * @return mixed
    */
    public function restore_existing_uploads( $entry, $form ) {
    if ( $form['id'] != $this->form_id ) return $entry;

    if ( $this->uploads ) foreach( $this->uploads as $u ) {
    if ( $entry['id'] != $u['entry_id'] ) continue;

    // Get the field ID and URL of the file that should be preserved
    $field_id = $u['field_id']; // 13
    $url = $u['url']; // https://example.com/.../icon-zm3.png

    // Restore the URL to the entry
    $entry[ $field_id ] = $url;

    // Update the entry
    GFAPI::update_entry( $entry );

    }

    return $entry;
    }


    /**
    * Make all fields on the form editable (allowPrepopulate) and add names if not already given.
    *
    * @param $form
    *
    * @return mixed
    */
    public function add_form_prepopulate_names( $form ) {
    // Modify every field and add a name if needed.
    // Names added manually work too, by enabling "Allow field to be populated dynamically" on the field.
    if ( $form['fields'] ) foreach( $form['fields'] as &$field ) {
    if ( !($field instanceof GF_Field) ) continue;

    // Don't affect display fields (like html)
    if ( $field->displayOnly ) continue;

    // Enable pre-populate
    $field->allowsPrepopulate = true;

    // Get regular field name
    $inputName = $field->inputName;
    if ( $inputName ) continue;

    // Check if we need a regular field name, or if we need sub fields with names.
    if ( empty( $field->inputs ) ) {

    // Regular field
    // 1st and 2nd are form ID ($form['id']), and field ID ($form->fields[0]->id)
    // field_12_4_value
    $field->inputName = "field_{$field['formId']}_{$field['id']}_value";

    }else{

    // Sub fields
    // Loop through sub fields and add names to any that are missing
    foreach( $field->inputs as $key => &$input ) {

    if ( empty($input['name']) ) {

    // 3rd number is the sub field ID: ($form->fields[0]->inputs[0]->id)
    // input name="field_12_4_1_value"
    $input['name'] = "sub_field_" . $field['formId'] . '_' . $field['id'] . '_'. $key .'_value';

    }

    }
    }
    }

    return $form;
    }


    /**
    * Fill the value on our form using the existing entry's data
    *
    * @param $value
    * @param GF_Field|null $field
    * @param $name
    *
    * @return array
    */
    public function load_regular_field_value( $value = null, GF_Field $field = null, $name = null ) {
    if ( ! ($field instanceof GF_Field) ) return $value;
    if ( $field->formId != $this->form_id ) return $value;

    $existing_entry_id = $this->get_edited_entry_id();
    if ( !$existing_entry_id ) return $value;

    $existing_entry = GFAPI::get_entry( $existing_entry_id );
    if ( !$existing_entry ) return $value;

    $value = GFFormsModel::get_lead_field_value( $existing_entry, $field );

    // If no sub fields just return value
    if ( empty($field->inputs) ) return $value;

    // Checkboxes work with the given value
    if ( $field->type == 'checkbox' ) return $value;

    // Names do not seem to work.

    return $value;
    }



    /**
    * Add certain hooks only when the form is going to be displayed (based on shortcode usage)
    *
    * $args = array(7) {
    * "form_id" => "12"
    * "display_title" => true
    * "display_description" => true
    * "force_display" => false
    * "field_values" => array() (empty)
    * "ajax" => false
    * "tabindex" => "0"
    * }
    *
    * @param $args
    * @return array
    */
    public function add_hooks_on_display( $args ) {
    public function prepare_editable_form( $args ) {
    // Only for this form
    if ( $this->form_id !== (int) $args['form_id'] ) return $args;

    // 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.
    $form = GFAPI::get_form( $this->form_id );

    $ignored_field_types = array('html', 'section', 'page');
    $compound_field_types = array('checkbox');
    $form = $this->add_form_prepopulate_names( $form );

    foreach( $form['fields'] as $field ) {
    if ( !($field instanceof GF_Field) ) continue;

    $name = rgobj( $field, 'inputName' );
    $type = rgobj( $field, 'type' );
    $sub_inputs = rgobj($field, 'inputs');

    // Always ignore certain field types
    if ( !$type ) continue;
    if ( in_array($type, $ignored_field_types) ) continue;

    // Compound inputs have just one name, but have multiple inputs with their own values.
    if ( in_array($type, $compound_field_types) ) {
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_field_value_compound' ), 20, 3 );
    continue;
    }

    // Standard inputs like text and selects have just one input name for the field with a single value.
    // And some like the Date field have one name with multiple inputs, but still just a single value.
    if ( $name ) {
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_field_value_text' ), 20, 3 );
    continue;
    }

    // Advanced inputs like Name and Address have multiple sub inputs, each with their own name and values
    // They are tricky to fill because Gravity Forms doesn't give you the key with this filter.
    if ( $sub_inputs ) {
    foreach( $sub_inputs as $sub_input ) {
    if ( !is_array($sub_input) ) continue;
    @@ -89,11 +333,11 @@ public function add_hooks_on_display( $args ) {
    $name = rgar($sub_input, 'name' );
    if ( !$name ) continue;

    // Store the sub input, particularly so we can get the ID later
    // Store the sub input field assigned to the name (first_name) so we can get field data later
    $this->sub_inputs[ $name ] = $sub_input;

    // Use a special filter for sub inputs
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_sub_input_value_text' ), 20, 3 );
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_sub_input_value' ), 20, 3 );
    }
    continue;
    }
    @@ -102,18 +346,6 @@ public function add_hooks_on_display( $args ) {
    return $args;
    }

    /**
    * Get the entry id that is being edited
    *
    * @return int|false
    */
    public function get_edited_entry_id() {
    $entry_id = (int) rgar( $_GET, 'entry_id' );
    if ( !$entry_id ) $entry_id = false;

    return $entry_id;
    }

    /**
    * Return true if the given user is able to make edits to the entry.
    *
    @@ -126,21 +358,26 @@ public function can_user_edit_entry( $user_id, $entry ) {
    if ( is_numeric($entry) ) $entry = GFAPI::get_entry( $entry );
    if ( !$entry || is_wp_error( $entry ) ) return false;

    // Must be an entry belonging to this renewal form
    // Must be an entry belonging to this 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;
    // The user ID must match the owner of the entry
    if ( (int) $entry['created_by'] != (int) $user_id ) return false;

    return true;
    }

    /**
    * Set up "uploaded_files" using values from the previous entry. Allows you to keep your previous upload, or remove it and start over.
    *
    * If file is kept, form submits:
    * gform_uploaded_files: {"input_13":"icon-aa3.png"}
    *
    * If file is removed, form submits:
    * gform_uploaded_files: {"input_13":null}
    *
    *
    *
    * @param $form
    * @param $ajax
    * @param $field_values
    @@ -153,6 +390,8 @@ public function prepare_previously_uploaded_files( $form, $ajax, $field_values )
    // Get the edited entry
    $entry_id = $this->get_edited_entry_id();
    if ( !$entry_id ) return $form;

    // Check permissions
    if ( !$this->can_user_edit_entry( $user_id, $entry_id ) ) return $form;

    // Check if any field is a file upload. If not, we can ignore this function
    @@ -181,18 +420,20 @@ public function prepare_previously_uploaded_files( $form, $ajax, $field_values )

    $value = rgar( $entry, $field->id );
    GFFormsModel::$uploaded_files[ $form['id'] ]["input_{$field->id}"] = basename( $value );


    }

    return $form;
    }

    /**
    * Allow editing previous form entry
    * Make Gravity Forms edit an existing entry ($entry_id = int), instead of creating a new one ($entry_id = null).
    *
    * @param $entry_id
    * @param $form
    * @param $entry_id null|int
    * @param $form array
    *
    * @return mixed
    * @return null|int
    */
    public function change_saved_entry_id( $entry_id, $form ) {
    if ( $entry_id !== null ) return $entry_id;
    @@ -203,78 +444,30 @@ public function change_saved_entry_id( $entry_id, $form ) {
    $existing_entry_id = $this->get_edited_entry_id();
    if ( !$existing_entry_id ) return $entry_id;

    // Use the edited entry if the user is permitted to edit it
    // Check access, if user can edit then return the previous entry ID, instead of creating a new one (null).
    if ( $this->can_user_edit_entry( $user_id, $existing_entry_id ) ) {

    // Edit previous entry
    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 ) {
    if ( $field->formId != $this->form_id ) return $value;

    $existing_entry_id = $this->get_edited_entry_id();

    if ( $existing_entry_id ) {
    $value = gform_get_meta( $existing_entry_id, $field['id'] );
    }

    return $value;
    }

    /**
    * Fill text fields with the value of an existing entry
    *
    * @param null $value
    * @param GF_Field|null $field
    * @param null $name
    *
    * @return array
    */
    public function fill_field_value_compound( $value = null, GF_Field $field = null, $name = null ) {
    if ( $field->formId != $this->form_id ) return $value;

    $sub_inputs = rgobj($field, 'inputs');
    if ( !$sub_inputs ) return $value;

    $existing_entry_id = $this->get_edited_entry_id();

    $value = array();

    }else{

    if ( $existing_entry_id ) {
    foreach( $sub_inputs as $sub_input ) {
    if ( !is_array($sub_input) ) continue;

    $sub_input_id = $sub_input['id'];
    $v = gform_get_meta( $existing_entry_id, $sub_input_id );

    if ( $v ) $value[] = $v;
    }
    // Create a new entry
    return null;

    }

    return $value;
    }

    /**
    * Same as fill_field_value_text, but for sub inputs which are recorded in $this->sub_inputs
    * Get text used for sub inputs
    *
    * @param null $value
    * @param GF_Field|null $field
    * @param null $name
    *
    * @return string
    */
    public function fill_sub_input_value_text( $value = null, GF_Field $field = null, $name = null ) {
    public function fill_sub_input_value( $value = null, GF_Field $field = null, $name = null ) {
    if ( $field->formId != $this->form_id ) return $value;

    // Name must be defined in $this->sub_inputs so we know what sub field this hook relates to.
  3. RadGH revised this gist Mar 31, 2021. 1 changed file with 2 additions and 18 deletions.
    20 changes: 2 additions & 18 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -105,28 +105,12 @@ public function add_hooks_on_display( $args ) {
    /**
    * Get the entry id that is being edited
    *
    * @return bool|int|mixed
    * @return int|false
    */
    public function get_edited_entry_id() {
    $evaluation_id = (int) rgar( $_GET, 'evaluation_id' );
    if ( !$evaluation_id ) return false;

    // Cache the entry_id for this evaluation for the session.
    static $cached_entry_ids = null;
    if ( $cached_entry_ids === null ) $cached_entry_ids = array();

    // Return from cache if set
    if ( isset($cached_entry_ids[$evaluation_id]) ) {
    return $cached_entry_ids[$evaluation_id];
    }

    // Get entry id from evaluation
    $entry_id = (int) get_field( 'entry_id', $evaluation_id );
    $entry_id = (int) rgar( $_GET, 'entry_id' );
    if ( !$entry_id ) $entry_id = false;

    // Cache the entry id for next occurrence
    $cached_entry_ids[$evaluation_id] = $entry_id;

    return $entry_id;
    }

  4. RadGH revised this gist Jul 14, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@
    // * This is a dumb restriction by GF as without a name, there is no filter to set the value.
    // * File inputs do not need a name though (they don't support one anyway).
    // 3. This is only for the front-end. I don't know why GF doesn't let you edit entries on the backend.
    abstract class Evaluation_Form_GF_Editable {
    abstract class Editable_GF_Form {

    // Form ID that will allow editing entries
    public $form_id = null;
  5. RadGH revised this gist Jul 14, 2020. 1 changed file with 142 additions and 25 deletions.
    167 changes: 142 additions & 25 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -10,55 +10,96 @@
    // 1. All fields must have a unique name set for "allow to be pre-populated".
    // * This is a dumb restriction by GF as without a name, there is no filter to set the value.
    // * File inputs do not need a name though (they don't support one anyway).
    // 2. Advanced fields or fields with more than one option may need their own hook set up in add_gravityform_editable_hooks().
    // * I added an example if statement for "type = text". Replace that with other field types and build your own hook to get the value.
    // 3. This is only for the front-end. I don't know why GF doesn't let you edit entries on the backend.
    abstract class Editable_GF_Form {
    abstract class Evaluation_Form_GF_Editable {

    // Form ID that will allow editing entries
    public $form_id = null;
    public $initialized = false;
    public $sub_inputs = array();

    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'
    ) );
    public function __construct() {;
    // Add other hooks on every page load -- for things like saving data
    add_action( 'after_setup_theme', array( $this, 'add_hooks_on_every_load' ) );

    // Add certain hooks only when the form is going to be displayed (based on shortcode usage)
    add_filter( 'gform_form_args', array( $this, 'add_hooks_on_display' ), 20 );
    }

    /**
    * Add hooks so that this form can be modified
    * Add hooks so that entry can save. This can happen on submit or ajax, the shortcode will not be processed so it needs a separate hook.
    */
    public function add_gravityform_editable_hooks() {
    // Form id must be specified
    public function add_hooks_on_every_load() {
    // Only for this form
    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, 'change_saved_entry_id'), 50, 2 );
    }

    /**
    * Add certain hooks only when the form is going to be displayed (based on shortcode usage)
    *
    * @param $args
    * @return array
    */
    public function add_hooks_on_display( $args ) {
    // Only for this form
    if ( $this->form_id !== (int) $args['form_id'] ) return $args;

    // 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.
    $form = GFAPI::get_form( $this->form_id );

    foreach( $form['fields'] as $i => $field ) {
    $ignored_field_types = array('html', 'section', 'page');
    $compound_field_types = array('checkbox');

    foreach( $form['fields'] as $field ) {
    if ( !($field instanceof GF_Field) ) continue;

    $name = rgobj( $field, 'inputName' ); // "evaluation_id"
    $type = rgobj( $field, 'type' ); // "hidden"
    $hook = false;
    $name = rgobj( $field, 'inputName' );
    $type = rgobj( $field, 'type' );
    $sub_inputs = rgobj($field, 'inputs');

    if ( $type == 'text' ) {
    $hook = 'fill_field_value_text'; // some other condition can be used here if text doesn't work
    }else{
    $hook = 'fill_field_value_text';
    // Always ignore certain field types
    if ( !$type ) continue;
    if ( in_array($type, $ignored_field_types) ) continue;

    // Compound inputs have just one name, but have multiple inputs with their own values.
    if ( in_array($type, $compound_field_types) ) {
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_field_value_compound' ), 20, 3 );
    continue;
    }

    // Standard inputs like text and selects have just one input name for the field with a single value.
    // And some like the Date field have one name with multiple inputs, but still just a single value.
    if ( $name ) {
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_field_value_text' ), 20, 3 );
    continue;
    }

    if ( $hook && $name ) {
    add_filter( "gform_field_value_{$name}", array($this, $hook), 20, 3 );
    // Advanced inputs like Name and Address have multiple sub inputs, each with their own name and values
    if ( $sub_inputs ) {
    foreach( $sub_inputs as $sub_input ) {
    if ( !is_array($sub_input) ) continue;

    // Get the name, if any
    $name = rgar($sub_input, 'name' );
    if ( !$name ) continue;

    // Store the sub input, particularly so we can get the ID later
    $this->sub_inputs[ $name ] = $sub_input;

    // Use a special filter for sub inputs
    add_filter( "gform_field_value_{$name}", array( $this, 'fill_sub_input_value_text' ), 20, 3 );
    }
    continue;
    }
    }

    return $args;
    }

    /**
    @@ -67,8 +108,24 @@ public function add_gravityform_editable_hooks() {
    * @return bool|int|mixed
    */
    public function get_edited_entry_id() {
    $entry_id = (int) rgar( $_GET, 'entry_id' );
    if ( !$entry_id ) return false;
    $evaluation_id = (int) rgar( $_GET, 'evaluation_id' );
    if ( !$evaluation_id ) return false;

    // Cache the entry_id for this evaluation for the session.
    static $cached_entry_ids = null;
    if ( $cached_entry_ids === null ) $cached_entry_ids = array();

    // Return from cache if set
    if ( isset($cached_entry_ids[$evaluation_id]) ) {
    return $cached_entry_ids[$evaluation_id];
    }

    // Get entry id from evaluation
    $entry_id = (int) get_field( 'entry_id', $evaluation_id );
    if ( !$entry_id ) $entry_id = false;

    // Cache the entry id for next occurrence
    $cached_entry_ids[$evaluation_id] = $entry_id;

    return $entry_id;
    }
    @@ -89,7 +146,7 @@ public function can_user_edit_entry( $user_id, $entry ) {
    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;
    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;
    @@ -191,4 +248,64 @@ public function fill_field_value_text( $value = null, GF_Field $field = null, $n
    return $value;
    }

    /**
    * Fill text fields with the value of an existing entry
    *
    * @param null $value
    * @param GF_Field|null $field
    * @param null $name
    *
    * @return array
    */
    public function fill_field_value_compound( $value = null, GF_Field $field = null, $name = null ) {
    if ( $field->formId != $this->form_id ) return $value;

    $sub_inputs = rgobj($field, 'inputs');
    if ( !$sub_inputs ) return $value;

    $existing_entry_id = $this->get_edited_entry_id();

    $value = array();

    if ( $existing_entry_id ) {
    foreach( $sub_inputs as $sub_input ) {
    if ( !is_array($sub_input) ) continue;

    $sub_input_id = $sub_input['id'];
    $v = gform_get_meta( $existing_entry_id, $sub_input_id );

    if ( $v ) $value[] = $v;
    }
    }

    return $value;
    }

    /**
    * Same as fill_field_value_text, but for sub inputs which are recorded in $this->sub_inputs
    *
    * @param null $value
    * @param GF_Field|null $field
    * @param null $name
    *
    * @return string
    */
    public function fill_sub_input_value_text( $value = null, GF_Field $field = null, $name = null ) {
    if ( $field->formId != $this->form_id ) return $value;

    // Name must be defined in $this->sub_inputs so we know what sub field this hook relates to.
    if ( !isset($this->sub_inputs[$name]) ) return $value;

    $id = rgar( $this->sub_inputs[$name], 'id' );
    if ( !$id ) return $value;

    $existing_entry_id = $this->get_edited_entry_id();

    if ( $existing_entry_id ) {
    $value = gform_get_meta( $existing_entry_id, $id );
    }

    return $value;
    }

    }
  6. RadGH revised this gist Jul 14, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -55,7 +55,7 @@ public function add_gravityform_editable_hooks() {
    $hook = 'fill_field_value_text';
    }

    if ( $hook ) {
    if ( $hook && $name ) {
    add_filter( "gform_field_value_{$name}", array($this, $hook), 20, 3 );
    }
    }
  7. RadGH revised this gist Jun 25, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,7 @@
    // * File inputs do not need a name though (they don't support one anyway).
    // 2. Advanced fields or fields with more than one option may need their own hook set up in add_gravityform_editable_hooks().
    // * I added an example if statement for "type = text". Replace that with other field types and build your own hook to get the value.
    // 3. This is only for the front-end. I don't know why GF doesn't let you edit entries on the backend.
    abstract class Editable_GF_Form {

    // Form ID that will allow editing entries
  8. RadGH revised this gist Jun 25, 2020. 1 changed file with 100 additions and 155 deletions.
    255 changes: 100 additions & 155 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -1,114 +1,99 @@
    <?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.
    // How to use:
    // 1. Create your own class that extends this one, such as: class Amazing_Quiz extends Editable_GF_Form {...}
    // 2. Set the $form_id in your class (Amazing_Quiz). *Note: This code is designed for a single form per class but could easily be adapted to support any form.
    // 3. Edit an entry by visiting your form normally but with ?entry_id=123 in the URL. If your user account created the entry, you can edit it.

    class Renewal {

    // Gravity Forms settings use during submission and to edit existing entries.
    public $form_id = 1;
    // Requirements:
    // 1. All fields must have a unique name set for "allow to be pre-populated".
    // * This is a dumb restriction by GF as without a name, there is no filter to set the value.
    // * File inputs do not need a name though (they don't support one anyway).
    // 2. Advanced fields or fields with more than one option may need their own hook set up in add_gravityform_editable_hooks().
    // * I added an example if statement for "type = text". Replace that with other field types and build your own hook to get the value.
    abstract class Editable_GF_Form {

    // 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' ),
    );
    // Form ID that will allow editing entries
    public $form_id = null;

    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' ) );
    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
    * Add hooks so that this form can be modified
    */
    public function can_user_edit_entry( $user_id, $entry_id ) {
    $entry = GFAPI::get_entry( $entry_id );
    if ( !$entry || is_wp_error($entry) ) return false;
    public function add_gravityform_editable_hooks() {
    // Form id must be specified
    if ( $this->form_id === null ) return;

    // Must be an entry belonging to this renewal form
    if ( $entry['form_id'] != $this->form_id ) return false;
    // 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, 'change_saved_entry_id'), 50, 2 );

    // Check if user is owner of the entry
    if ( (int) $entry['created_by'] != (int) $user_id ) return false;
    // 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 );

    // Check if status of entry is no longer "active". Only active entries can be edited
    if ( $entry['status'] !== 'active' ) return false;
    // Fill in the value of all fields that have a name. The name must match the "autofill parameter name" in the field's settings.
    $form = GFAPI::get_form( $this->form_id );

    return true;
    foreach( $form['fields'] as $i => $field ) {
    if ( !($field instanceof GF_Field) ) continue;

    $name = rgobj( $field, 'inputName' ); // "evaluation_id"
    $type = rgobj( $field, 'type' ); // "hidden"
    $hook = false;

    if ( $type == 'text' ) {
    $hook = 'fill_field_value_text'; // some other condition can be used here if text doesn't work
    }else{
    $hook = 'fill_field_value_text';
    }

    if ( $hook ) {
    add_filter( "gform_field_value_{$name}", array($this, $hook), 20, 3 );
    }
    }
    }

    /**
    * Get the user's current inactive pli renewal entry
    * - Must be active (not trashed)
    * - Must be created by the user_id
    * Get the entry id that is being edited
    *
    * @param $user_id
    *
    * @return int|false
    * @return bool|int|mixed
    */
    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;
    }
    public function get_edited_entry_id() {
    $entry_id = (int) rgar( $_GET, 'entry_id' );
    if ( !$entry_id ) return false;

    return $entry_id;
    }
    /**
    * Add hooks so that this form can be modified
    * Return true if the given user is able to make edits to the entry.
    *
    * @param int $user_id
    * @param array|int $entry
    *
    * @return bool
    */
    public function add_gravityform_editable_hooks() {
    // Form id must be specified
    if ( $this->form_id === null ) return;
    public function can_user_edit_entry( $user_id, $entry ) {
    if ( is_numeric($entry) ) $entry = GFAPI::get_entry( $entry );
    if ( !$entry || is_wp_error( $entry ) ) return false;

    // 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 );
    // Must be an entry belonging to this renewal form
    if ( $entry['form_id'] != $this->form_id ) return false;

    // 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 );
    // Check if user is owner of the entry
    if ( (int) $entry['created_by'] != (int) $user_id ) return false;

    // 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;

    }
    }
    // Check if status of entry is no longer "active". Only active entries can be edited
    if ( $entry['status'] !== 'active' ) return false;

    return true;
    }

    /**
    @@ -123,56 +108,42 @@ public function add_gravityform_editable_hooks() {
    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;
    // Get the edited entry
    $entry_id = $this->get_edited_entry_id();
    if ( !$entry_id ) return $form;
    if ( !$this->can_user_edit_entry( $user_id, $entry_id ) ) return $form;

    // Check if any field is a file upload. If not, we can ignore this function
    do {
    foreach( $form['fields'] as $field ) {
    if ( $field instanceof GF_Field_FileUpload ) {
    // File upload found. Abort the do{} loop and proceed with the function
    break 2;
    }
    }

    // No file uploads found
    return $form;
    } while(false);

    // Get the entry object
    $entry = GFAPI::get_entry( $entry_id );

    if ( !isset(GFFormsModel::$uploaded_files[$form['id']]) ) {
    GFFormsModel::$uploaded_files[$form['id']] = array();
    if ( !isset( GFFormsModel::$uploaded_files[ $form['id'] ] ) ) {
    GFFormsModel::$uploaded_files[ $form['id'] ] = array();
    }

    // Loop through each file upload and put the basename as an uploaded file
    foreach( $form['fields'] as $field ) {
    if ( ! $field instanceof GF_Field_FileUpload ) continue;
    if ( !$field instanceof GF_Field_FileUpload ) continue;

    $value = rgar( $entry, $field->id );
    GFFormsModel::$uploaded_files[$form['id']]["input_{$field->id}"] = basename($value);
    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
    *
    @@ -181,20 +152,16 @@ public function get_field_definition_by_field_name( $value ) {
    *
    * @return mixed
    */
    public function edit_existing_entry( $entry_id, $form ) {
    public function change_saved_entry_id( $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 );
    // Get the entry being edited
    $existing_entry_id = $this->get_edited_entry_id();
    if ( !$existing_entry_id ) return $entry_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.
    // Use the edited entry if the user is permitted to edit it
    if ( $this->can_user_edit_entry( $user_id, $existing_entry_id ) ) {
    return $existing_entry_id;
    }
    @@ -212,34 +179,12 @@ public function edit_existing_entry( $entry_id, $form ) {
    * @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 ( $field->formId != $this->form_id ) return $value;

    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();
    $existing_entry_id = $this->get_edited_entry_id();

    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 );
    }
    $value = gform_get_meta( $existing_entry_id, $field['id'] );
    }

    return $value;
  9. RadGH revised this gist Apr 7, 2020. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,14 @@
    <?php
    if ( !defined( 'ABSPATH' ) ) exit;

    abstract class Renewal {
    // 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 = null;
    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.
  10. RadGH revised this gist Apr 7, 2020. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -6,10 +6,10 @@ abstract class Renewal {
    // Gravity Forms settings use during submission and to edit existing entries.
    public $form_id = null;

    // 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.
    // 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' ),
  11. RadGH created this gist Apr 7, 2020.
    244 changes: 244 additions & 0 deletions edit-gf-entry.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,244 @@
    <?php
    if ( !defined( 'ABSPATH' ) ) exit;

    abstract class Renewal {

    // Gravity Forms settings use during submission and to edit existing entries.
    public $form_id = null;

    // 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;
    }

    }