E Signature – Programmatically Save Contract

The Approve Me E-Signature plugin is used to create legally binding electronic contracts that can be populated by Gravity Form and data.

Whilst it can be easily used within a Gravity Forms workflow, and even with Gravity Flow. There is little to no ability when it comes to using it in the backend with action hooks. Therefore if you want to do anything automatically with the signed document there is little support but fortunately a solution has been found.

This blog will describe the steps and reasons behind in order to succesfully hook into E signature upon completion of the signing of a document.

Deducing the Solution

In the real world example it was required that a contract is available to view in the respective signer’s “Document Vault” inside of a Gravity View. This meant understanding what E Signature does to a signed document.

There is a section in the plugin page that shows all signed contracts and gives the option to view them.

Clicking view takes us to a page with a URL similar to this

https://website.com/e-signature-document-2/?esigpreview=1&document_id=40

What this shows is that all that is required to view a specific signed document is the variable “document_id” but comparing it to other signed contracts shows that this ID is not related to anything other than what is generated at the time by the plugin upon signing.

The Hook and Why We Need It

What the previous section revealed is that the unique identifier required to view a signed document only relates to something the plugin itself does when it generates the signed document. Therefore we must hook into the plugin to be able to programmatically store the link to view a specific document.

Approve Me, the maker’s of the E Signature plugin, do not have great documentation regarding back end manipulation and it appears that there are no hooks designed to be used by external programmers.

Fortunately, the plugin itself uses hooks to work and there is more than likely one that is triggered upon completion of a document being signed, regardless of what it may do. This isn’t enough though as what is required ultimately is the document id. So overall we need a hook that triggers upon completion of the signing of the document and also takes in the document id, or an object that contains it.

In this case, looking through the plugins files, a file called actions.php had a list of actions the plugin uses. One action looked like this

function save_signer_screen_width($args) {
    
      $screen_width = sanitize_text_field(esigpost('esig_screen_width'));
      if(!$screen_width){
          return false;
      }
      if(!is_numeric($screen_width)){
          return false;
      }
      
      $signature_id = esigget("signature_id",$args);
      
      $invitation = esigget("invitation",$args);
      
      WP_E_Sig()->meta->add($invitation->document_id,"signer-screen-width-".$signature_id,$screen_width);    
    
}
add_action("esig_signature_saved", "save_signer_screen_width", -100, 1);

This action does a simple thing, it saves the screen resolution when a signer signs a document. It adds this to a document’s meta values and therefore we now know how to get the document id within this action which is triggered upon completion of signing.

Now we have everything we need to create a script that can do anything we want with a signed document.

Step by Step Implentation

Step 1: Create New File

Create a new PHP file that will simply hold the function and action hook. This will then be added to a custom plugin for whatever website you are using.

Step 2: Getting the Document ID

function update_master_on_sign($args) {
write_log("IN CONTRACT HOOK");

//$documentContentUnfilter = WP_E_Sig()->document->esig_do_shortcode($doc_id);

    //$document_content = WP_E_Sig()->signature->encrypt(ENCRYPTION_KEY, $documentContentUnfilter);
    //$document_checksum = sha1($doc_id . $documentContentUnfilter);
    //Esign_Query::_update("documents", array("document_content" => $document_content, "document_checksum" => $document_checksum), array("document_id" => $doc_id), array("%s", "%s"), array("%d"));
    //Esign_Query::_update("documents",array("document_content"=>$document_content),array("document_id"=>$doc_id),array("%s"),array("%d"));

// Get Document ID
    $invitation = esigget("invitation",$args);
    $doc_id = $invitation->document_id;

    write_log("DOCUMENT ID");
    write_log($doc_id);

//  Get current user ID
    $userID = get_current_user_id();

//  Get user's Master Form Entry
    $repeater_master_form_id = 1;

    $repeater_master_search_criteria['field_filters'][] = array('key' => 'created_by', 'value' => $userID);
    $repeater_master_search_criteria['status'] = 'active';
    $repeater_master_sorting = array('key' => 'id', 'direction' => 'ASC', 'is_numeric' => true);
    $master_entries = GFAPI::get_entries($repeater_master_form_id, $repeater_master_search_criteria, $repeater_master_sorting);
    
// Add link to contract in gravity form field
    $master_entries[0][127] = "https://texas.divorceconcierge.com/e-signature-document/?esigpreview=1&document_id=".$doc_id;

//  Update the entry to confirm the changes
    $update_entry = GFAPI::update_entry($master_entries[0]);

}   

add_action("esig_signature_saved", "update_master_on_sign", -100, 1);

*FOR COPYING AND PASTING PURPOSES*

In this example, after writing to log to test it is firing correctly (on line 22) it uses the same line to get us to an object with the document id which we can then extract in the following line and store in a variable.

Step 3: Getting the User ID

As it is likely that you will need to use the contract with something else that is specific to the user, you will need to get the user id and store it in a variable. Fortunately there is a simple function to do it.

get_current_user_id();

As the contract is signed and therefore this action is triggered by the user (client of website), we know the id returned will be what we want.

Step 4: Getting the Gravity Form Entry

This may not apply to you but the principle remains the same in terms of accessing an object to place the contract inside.

In this example, I am accessing a Gravity Form using the “created_by” as the search criteria and using the $userID we retrieved earlier to be searched against. This will give me (most likely) 1 entry of that form within the variable $master_entries and as this is contained in an array, will need to be accessed like so, “$master_entries[0]”.

Step 5: Create the Link Variable

The last thing before updating the entry is to actually create what we need, which is the link to view the document. As mentioned, each document has an ID generated upon creation and that is used in a query in the URL, so all we have to do is get a link to a document and add the document ID variable to the end of it, and then store the whole thing in a variable. It would look like this.

$documentLink = 'https://mywebsite.com/esignaturedocument/e-sigpreview=1&document_id=' . $documentID;

Step 6: Update the Entry

At this point in the code we have the:

  • Document ID from the contract just signed
  • ID of the user who signed
  • Gravity Form entry of the user who signed
  • URL for viewing the document

The last thing to do is to bring it all together and add the url to a Gravity Form field in the user’s Gravity Form entry.

To do this, we use the API function,

 GFAPI::update_entry()

This takes an entry object and will replace the one currently saved on the server with the data contained in the object used in the function.

Before we do this we need to modify the entry by replacing a value, this can be done like this:

$master_entries[0]['50'] = 'New Variable';

The entry we retrieved earlier is technically part of an array of entries, but as only the one we are looking for fit the criteria, it is the first object in the array. The entry itself is also an array so to specify a field, we just specify its ID. And then to change it you say that it equals something else.

Now that that is occured, the object “master_entries[0]” will contain the URL to view the document and so that these changes are on the server, we simply add the entry object as the parameter of the function, like this:

$updated_entry = GFAPI::update_entry($master_entries[0]);

Conclusion:

This tutorial explained a very useful piece of code but it also highlighted a principal. The developers of the plugin did not create action hooks for user’s to use openly, but it was impossible to achieve the outcome that was required. This may happen often so it is important to look in a plugins files to see if an outcome is possible by simply using a hook they already use.

Regarding this solution specifically, this can be used on any site using approve me E-Signature plugin and could be used for many things that may simply require the knowledge of a recently signed contract.