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, 2020 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, 2020 at 10:53


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.