I'm having trouble figuring out where I should be registering my function in such a way that I can access the Gravity Forms API (GFAPI). At first glance, this may appear to be native to Gravity Forms, but I think I'm just missing some basic understanding of how WordPress uses hooks and registers functions.

The error I'm trying to resolve is that class_exists("GFForms") returns false (i.e. my code can't access the API) in a context where I want it to return true.

I'm trying to take an XML, parse it, and use some of the data to generate a gravity forms entry. My starting point was the Gravity Forms Simple AddOn (https://github.com/gravityforms/simpleaddon) as, to my knowledge, this is the direction I probably need to head since I'm wanting to access the GFAPI (correct me if I'm wrong there).

1) To start, I create a bootstrap file responsible for making GravityForms aware of the AddOn (abcd_import.php):

 * Plugin Name: ABCD Utility
 * Plugin URI: https://www.abcd.com
 * Description: Display content using a shortcode to insert in a page or post
 * Version: 1
 * Text Domain: abcd-import-utility
 * Author: me
 * Author URI: https://www.abcd.com
define( 'GF_abcd_IMPORT_VERSION', '1.0' );
add_action( 'gform_loaded', array( 'abcd_Import_Bootstrap', 'load' ), 5 );
class abcd_Import_Bootstrap {
    public static function load() {
        if ( ! method_exists( 'GFForms', 'include_addon_framework' ) ) {
        require_once( 'class-abcd.php' );
        GFAddOn::register( 'GFabcdImport' );
function gf_abcd_import() {
    return GFabcdImport::get_instance();

2) The following class (in class-abcd.php) contains the function that creates a shortcode, which creates a form, which calls 'process_xml.php'. Before I had it set up so that both the 'add_abcd_import_fields' and 'add_shortcode' functions were outside the class. When they were outside the class, I could add the shortcode which successfully added the form (but no API access).

// This file is responsible for the nuts and bolts of declaring the AddOn to Gravity Forms
// Additionally, it provides a framework for in-depth customization of settings in three places:
// 1) Forms > ABCD Importer (when plugin_page() is active) 
// 2) Forms > Settings > ABCD Importer
// 3) Forms > Form(i.e. Edit) > Settings > ABCD Importer
// Since this AddOn doesn't really have 'settings' in that it's supposed to handle stuff automatically,
// I've deactivated (commented) all of the settings fields. I've left them as I suspect I will probably 
// want to add field mapping later and this is probably where I need to do it (thus everything that is 
// currently commented will serve its purpose as example code later)

class GFabcdImport extends GFAddOn {
    protected $_version = GF_ABCD_IMPORT_VERSION;
    protected $_min_gravityforms_version = '1.9';
    protected $_slug = 'gfabcdimport';
    protected $_path = 'plugin-folder-path/abcd_import.php';
    protected $_full_path = __FILE__;
    protected $_title = 'ABCD Import Utility';
    protected $_short_title = 'ABCD Importer';
    private static $_instance = null;
    public static function get_instance() {
        if ( self::$_instance == null ) {
            self::$_instance = new GFabcdImport();
        return self::$_instance;
    public function init() {
        add_filter( 'gform_submit_button', array( $this, 'form_submit_button' ), 10, 2 );       
        add_shortcode('add-custom-form', 'add_abcd_import_fields');
    public function scripts() {
        $scripts = array(
                'handle'  => 'my_script_js',
                'src'     => $this->get_base_url() . '/js/my_script.js',
                'version' => $this->_version,
                'deps'    => array( 'jquery' ),
                'strings' => array(
                    'first'  => esc_html__( 'First Choice', 'gfabcdimport' ),
                    'second' => esc_html__( 'Second Choice', 'gfabcdimport' ),
                    'third'  => esc_html__( 'Third Choice', 'gfabcdimport' )
                'enqueue' => array(
                        'admin_page' => array( 'form_settings' ),
                        'tab'        => 'gfabcdimport'
        return array_merge( parent::scripts(), $scripts );
    public function styles() {
        $styles = array(
                'handle'  => 'gf_abcd_styles_css',
                'src'     => $this->get_base_url() . '/css/gf_abcd_styles.css',
                'version' => $this->_version,
                'enqueue' => array(
                    array( 'field_types' => array( 'poll' ) )
        return array_merge( parent::styles(), $styles );
    function form_submit_button( $button, $form ) {
        $settings = $this->get_form_settings( $form );
        if ( isset( $settings['enabled'] ) && true == $settings['enabled'] ) {
            $text   = $this->get_plugin_setting( 'mytextbox' );
            $button = "<div>{$text}</div>" . $button;
        return $button;
    //This adds an entry under Forms in the WP context menu
    /*public function plugin_page() {
       echo 'This page appears in the Forms menu';
    //This displays settings in the Forms context menu: Settings > ABCD Importer
    public function plugin_settings_fields() {
        return array(
                'title'  => esc_html__( 'ABCD Import Utility Settings', 'gfabcdimport' ),
                'fields' => array(
                        'name'              => 'mytextbox',
                        'tooltip'           => esc_html__( 'This is the tooltip', 'gfabcdimport' ),
                        'label'             => esc_html__( 'This is the label', 'gfabcdimport' ),
                        'type'              => 'text',
                        'class'             => 'small',
                        'feedback_callback' => array( $this, 'is_valid_setting' ),
    //This displays settings in Forms > Form(i.e. Edit) > Settings > ABCD Importer  (unused, so most of it is commented out)  
    public function form_settings_fields( $form ) {
        return array(
                'title'  => esc_html__( 'ABCD Importer Settings', 'gfabcdimport' ),
                'fields' => array(
                    /* big chunk of commented out code I don't need */
    //artifact from the skeleton
    public function settings_my_custom_field_type( $field, $echo = true ) {
        echo '<div>' . esc_html__( 'My custom field contains a few settings:', 'simpleaddon' ) . '</div>';
        // get the text field settings from the main field and then render the text field
        $text_field = $field['args']['text'];
        $this->settings_text( $text_field );
        // get the checkbox field settings from the main field and then render the checkbox field
        $checkbox_field = $field['args']['checkbox'];
        $this->settings_checkbox( $checkbox_field );
    public function is_valid_setting( $value ) {
        return strlen( $value ) > 5;

    function add_abcd_import_fields($atts) {    
        $Content = "<form id='abcd_form' method='post' action='..\wp-content\plugins\plugin-folder-path\process_xml.php' enctype='multipart/form-data'>";
        $Content .= "<label id='abcd_form_label' for='abcd_form_select'>Form Type</label>";
        $Content .= "<select id='abcd_form_select' name='abcd_form_select' form='abcd_form'>";
        $Content .= "<option value='optA' selected>Option A</option>";
        $Content .= "<option value='optB'>Option B</option>";
        $Content .= "</select></br>";
        $Content .= "<label id='abcd_file_label' for='abcd_file'>File</label>";
        $Content .= "<input type='file' id='abcd_file' name='abcd_file'></br>";
        $Content .= "<input type='submit' id='abcd_submit_btn' name='abcd_submit_btn' value='Submit'>";
        $Content .= "</form>";
        return $Content;

    //public function add_custom_shortcode($atts){
        /* use [add-custom-form] as shortcode */
      //  add_shortcode('add-custom-form', 'add_abcd_import_fields');

3) The HTML form created from the shortcode calls 'process_xml.php' through it's action attribute. At the end of this file I attempt to a call a function 'generate_A' which fails because GFForms is unavailable. Regardless of what I do (read: where I move my functions around, the filters I add, etc.), I can't seem to get at the GFAPI. My only conclusion is that I'm just doing something dumb.

//initialize variables
$fileTmpPath = $fileName = $fileSize = $fileType = $fileNameCmps = $fileExtension = $newFileName = '';
$uploadFileDir = './tmpXML/';
$type = '';

function sanitize_inputs($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data);
    return $data;

  if (isset($_POST['abcd_submit_btn']) && $_POST['abcd_submit_btn'] == 'Submit') {
    if (isset($_FILES['abcd_file']) && $_FILES['abcd_file']['error'] === UPLOAD_ERR_OK) {
        $fileTmpPath = $_FILES['abcd_file']['tmp_name'];
        $fileName = $_FILES['abcd_file']['name'];
        $fileSize = $_FILES['abcd_file']['size'];
        $fileType = $_FILES['abcd_file']['type'];
        $fileNameCmps = explode(".", $fileName);
        $fileExtension = strtolower(end($fileNameCmps));

        //sanitize filename
        $newFileName = md5(time() . $fileName) . '.' . $fileExtension;

        $allowedfileExtensions = array('xml');
        if (in_array($fileExtension, $allowedfileExtensions)) {
                // directory in which the uploaded file will be moved                
                $dest_path = $uploadFileDir . $newFileName;
                $type = sanitize_inputs($_POST['abcd_form_select']);
                if(move_uploaded_file($fileTmpPath, $dest_path))
                    $message ='File upload successful.';                    
                    $message = 'There was some error moving the file to upload directory. Please make sure the upload directory is writable by web server.';

function process_file($type, $XMLFile){
    $dom = new DOMDocument;    
    $jsonArr = array();
    $gravityArr[] = null;

    //Pattern to identify elements with a name of "PXXX' where 'XXX' is an integer
    $pattern = '/P\\d*/';
    //Cycle through the DOM elements and save what we want to an array in json format
    foreach($dom->getElementsByTagName('*') as $abcd_component){
            $jsonArr['name'] = $abcd_component->getAttribute('name');
            $jsonArr['text'] = $abcd_component->getAttribute('text');
            array_push($gravityArr, $jsonArr);
    switch ($type){
        case 'optA':
        case 'optB':
            //generate_B($gravityArr); //TODO

function generate_A($gravityArr){
    //$ABCDImport = new GFabcdImport; //doesn't work, can't access GFAPI
    if (class_exists("GFForms")) { //class_exists returns 'false'
        $test = new GFForms; //help me get here please :)
        $test2 = '';

Gratitude to anyone that can point me in the right direction on this. Thanks so much!

  • The quick version is that you're posting data to process_xml.php which is separate code not loaded by WordPress and so you'd need to require wp-load.php to have access to the WordPress classes. The longer version is that you should ideally find a way to post the data to something controlled by WordPress instead I'd think, e.g. put this code in your theme and then have a page with a specific template which you post data to and that runs this code. But I don't really know what to recommend there, so I'll leave it to someone else to write a sensible answer. – Rup Aug 4 '20 at 10:51
  • (Or ideally we'd have a canonical answer to 'how to I post a form to arbitrary PHP I wrote' somewhere, since this comes up a fair bit.) – Rup Aug 4 '20 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.