Link to home
Start Free TrialLog in
Avatar of Chris Slack
Chris Slack

asked on

Wordpress site won't load.

Move a Wordpress site from wildwestdomains (Godaddy's Sister) Deluxe hosting to Godaddy Deluxe hosting CPanel site. The site won't load I get this from error log. I did not design this and I have never moved WP sites before so any help would be great.

[03-Oct-2019 08:11:45 UTC] PHP Fatal error:  Uncaught Error: Call to undefined function site_url() in /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/gravityforms/includes/webapi/webapi.php:21
Stack trace:
#0 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/gravityforms/gravityforms.php(162): require_once()
#1 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-settings.php(305): include_once('/home/mivn8z69y...')
#2 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-config.php(179): require_once('/home/mivn8z69y...')
#3 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-load.php(37): require_once('/home/mivn8z69y...')
#4 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-blog-header.php(13): require_once('/home/mivn8z69y...')
#5 /home/mivn8z69yz1h/public_html/danatannenbaummd.com/index.php(17): require('/home/mivn8z69y...')
#6 {main}
  thrown in /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/gravityforms/includes/webapi/webapi.php on line 21

Open in new window


Line 21 is:
define( 'GFWEBAPI_API_BASE_URL', site_url( GFWEBAPI_SLUG ) );

the PHP is:
<?php

if ( ! class_exists( 'GFForms' ) ) {
	die();
}


if ( ! defined( 'GFWEBAPI_REQUIRE_SIGNATURE' ) ) {
	define( 'GFWEBAPI_REQUIRE_SIGNATURE', true );
}

if ( ! defined( 'GFWEBAPI_SLUG' ) ) {
	define( 'GFWEBAPI_SLUG', 'gravityformsapi' );
}

if ( ! defined( 'GFWEBAPI_ROUTE_VAR' ) ) {
	define( 'GFWEBAPI_ROUTE_VAR', 'gfapi_route' );
}

if ( ! defined( 'GFWEBAPI_API_BASE_URL' ) ) {
	define( 'GFWEBAPI_API_BASE_URL', site_url( GFWEBAPI_SLUG ) );
}

if ( class_exists( 'GFForms' ) ) {
	GFForms::include_addon_framework();

	class GFWebAPI extends GFAddOn {
		protected $_version = '1.0';
		protected $_min_gravityforms_version = '1.7.9999';
		protected $_slug = 'gravityformswebapi';
		protected $_path = 'gravityformswebapi/webapi.php';
		protected $_full_path = __FILE__;
		protected $_url = 'https://www.gravityforms.com';
		protected $_title = 'Gravity Forms REST API';
		protected $_short_title = 'REST API';

		private $_enabled_v1;
		private $_enabled_v2;

		private $_private_key;
		private $_public_key;

		// Members plugin integration
		protected $_capabilities = array( 'gravityforms_api', 'gravityforms_api_settings' );

		// Permissions
		protected $_capabilities_settings_page = 'gravityforms_api_settings';
		protected $_capabilities_uninstall = 'gravityforms_webapi_uninstall';

		public function __construct() {
			global $_gaddon_posted_settings;

			if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
				add_action( 'gravityforms_results_cron_' . $this->_slug, array( $this, 'results_cron' ), 10, 3 );

				return;
			}

			$is_v2_enabled = $this->is_v2_enabled( $this->get_plugin_settings() ) || $this->is_v2_enabled();
			if ( $is_v2_enabled  ) {

				$this->maybe_upgrade_schema();

				if ( ! is_admin() ) {
					require_once( plugin_dir_path( __FILE__ ) . 'v2/class-gf-rest-authentication.php' );
				}
			}

			// Clear the settings cache because it was checked very early before other add-ons have a chance to make adjustments.
			$_gaddon_posted_settings = null;

			parent::__construct();
		}

		/***
		 * Updates REST API related schema when GF version changes
		 *
		 * @since 2.4-beta-1
		 */
		public function maybe_upgrade_schema() {

			global $wpdb;

			if ( $this->requires_schema_upgrade() ) {

				$collate = $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : '';
				$table_name = GFFormsModel::get_rest_api_keys_table_name();

				$table = "CREATE TABLE {$table_name} (
  key_id BIGINT UNSIGNED NOT NULL auto_increment,
  user_id BIGINT UNSIGNED NOT NULL,
  description varchar(200) NULL,
  permissions varchar(10) NOT NULL,
  consumer_key char(64) NOT NULL,
  consumer_secret char(43) NOT NULL,
  nonces longtext NULL,
  truncated_key char(7) NOT NULL,
  last_access datetime NULL default null,
  PRIMARY KEY  (key_id),
  KEY consumer_key (consumer_key),
  KEY consumer_secret (consumer_secret)
) $collate;";

				gf_upgrade()->dbDelta( $table );

				update_option( 'gf_rest_api_db_version', GFForms::$version );
			}
		}

		/**
		 * Returns true if REST API schema needs to be upgraded. False otherwise.
		 *
		 * @since 2.4-beta-1
		 *
		 * @return bool
		 */
		public function requires_schema_upgrade() {

			$rest_api_db_version = get_option( 'gf_rest_api_db_version' );

			$upgrade_required = version_compare( GFForms::$version, $rest_api_db_version, '>' );

			if ( $upgrade_required ) {

				// Making sure version has really changed. Gets around aggressive caching issue on some sites that cause setup to run multiple times.
				$rest_api_db_version = gf_upgrade()->get_wp_option( 'gf_rest_api_db_version' );

				$upgrade_required = version_compare( GFForms::$version, $rest_api_db_version, '>' );
			}

			return $upgrade_required;
		}

		public function init_ajax() {
			parent::init_ajax();
			add_action( 'wp_ajax_gfwebapi_qrcode', array( $this, 'ajax_qrcode' ) );

			add_action( 'wp_ajax_delete_key', array( $this, 'ajax_delete_key' ) );
		}

		public function init_admin() {
			parent::init_admin();

			if( GFForms::get_page() == 'settings' && rgget( 'subview' ) == $this->_slug ) {
				require_once( plugin_dir_path( __FILE__ ) . 'includes/class-gf-api-keys-table.php' );
			}

			// update the results cache meta
			add_action( 'gform_after_update_entry', array( $this, 'entry_updated' ), 10, 2 );
			add_action( 'gform_update_status', array( $this, 'update_entry_status' ), 10, 2 );
			add_action( 'gform_after_save_form', array( $this, 'after_save_form' ), 10, 2 );
		}

		public function init_frontend() {
			parent::init_frontend();
			$settings           = $this->get_plugin_settings();
			$this->_enabled_v1  = $this->is_v1_enabled( $settings );
			$this->_enabled_v2  = $this->is_v2_enabled( $settings );
			$this->_public_key  = rgar( $settings, 'public_key' );
			$this->_private_key = rgar( $settings, 'private_key' );

			if ( $this->_enabled_v1 ) {
				$this->init_v1();
			}

			if ( $this->_enabled_v2 ) {
				$this->init_v2();
			}

		}

		public function init_v1() {

			add_rewrite_rule( GFWEBAPI_SLUG . '/(.*)', 'index.php?' . GFWEBAPI_ROUTE_VAR . '=$matches[1]', $after = 'top' );

			$rules = get_option( 'rewrite_rules' );
			if ( ! isset( $rules[ GFWEBAPI_SLUG . '/(.*)' ] ) ) {
				flush_rewrite_rules();
			}

			add_filter( 'query_vars', array( $this, 'query_vars' ) );

			add_action( 'template_redirect', array( $this, 'handle_page_request' ) );

			// update the cache
			add_action( 'gform_entry_created', array( $this, 'entry_created' ), 10, 2 );

		}

		public function init_v2() {
			require_once( plugin_dir_path( __FILE__ ) . 'v2/restapi.php' );
		}

		public function load_text_domain() {
			GFCommon::load_gf_text_domain();
		}

		// Scripts
		public function scripts() {
			$min     = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
			$scripts = array(
				array(
					'handle'  => 'wp-lists',
					'enqueue' => array(
						array( 'admin_page' => array( 'plugin_settings' ) ),
					),
				),
				array(
					'handle'  => 'gfwebapi_hmac_sha1',
					'src'     => GFCommon::get_base_url() . '/includes/webapi/js/hmac-sha1.min.js',
					'enqueue' => array(
						array( 'admin_page' => array( 'plugin_settings' ) ),
					)
				),
				array(
					'handle'   => 'gfwebapi_enc_base64',
					'src'      => GFCommon::get_base_url() . '/includes/webapi/js/enc-base64-min.js',
					'deps'     => array( 'gfwebapi_hmac_sha1' ),
					'callback' => array( $this, 'localize_form_settings_scripts' ),
					'enqueue'  => array(
						array( 'admin_page' => array( 'plugin_settings' ) ),
					)
				),
				array(
					'handle'  => 'gfwebapi_settings.js',
					'src'     => GFCommon::get_base_url() . "/includes/webapi/js/gfwebapi_settings{$min}.js",
					'version' => $this->_version,
					'deps'    => array( 'jquery', 'thickbox' ),
					'enqueue' => array(
						array( 'admin_page' => array( 'plugin_settings' ) ),
					)
				),
			);

			return array_merge( parent::scripts(), $scripts );
		}

		public function styles() {
			$min    = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
			$styles = array(
				array(
					'handle'  => 'gfwebap_settings',
					'src'     => GFCommon::get_base_url() . "/includes/webapi/css/gfwebapi_settings{$min}.css",
					'version' => $this->_version,
					'deps'    => array( 'thickbox' ),
					'enqueue' => array(
						array( 'admin_page' => array( 'plugin_settings' ) ),
					)
				),
			);

			return array_merge( parent::styles(), $styles );
		}

		public function render_uninstall() {
		}

		// ------- Plugin settings -------

		public function settings( $sections ) {

			if ( rgget( 'action' ) == 'edit' ) {
				$this->api_key_edit_page();
			} else {
				parent::settings( $sections );
			}
		}

		public function api_key_edit_page() {
			$key_id = rgget( 'key_id' );

			$result = $this->maybe_save_api_key();

			if ( $result && ! empty( $result['consumer_key'] ) ) {
				$this->display_api_key_confirmation( $result );
			} else {

				$this->display_api_key_edit( $key_id, $result !== false );
			}
		}

		public function maybe_save_api_key() {

			if ( rgpost( 'update_key' ) ) {
				$key_id = rgget( 'key_id' );

				$key = array(
					'description' => sanitize_title( rgpost( 'key_description' ) ),
					'user_id' => absint( rgpost( 'key_user' ) ),
					'permissions' => rgpost( 'key_permission' ),
				);
				$result = $this->update_api_key( $key_id, $key );

				return $result;
			}
			return false;
		}

		public function display_api_key_confirmation( $api_key ) {

			?>

			<table class="form-table gforms_form_settings">
				<tbody><tr id="gaddon-setting-row-public_key">
					<th><?php esc_html_e( 'Consumer Key', 'gravityforms' )?></th>
					<td>
						<input type="text" name="consumer_key" id="consumer_key" value="<?php echo $api_key['consumer_key'] ?>" class="medium gaddon-setting gaddon-text">
					</td>
				</tr>
				<tr>
					<th><?php esc_html_e( 'Consumer Secret', 'gravityforms' )?></th>
					<td>
						<input type="text" name="consumer_secret" id="consumer_secret" value="<?php echo $api_key['consumer_secret'] ?>" class="medium gaddon-setting gaddon-text">
					</td>
				</tr>
				<tr>
					<th colspan="2">
						<div class="alert_yellow" style="padding:15px;">
							<?php esc_html_e( 'Make sure you have copied the consumer key and secret above. They will not be available once you leave this page', 'gravityforms' ) ?>
						</div>
					</th>
				</tr>
				<tr>
					<th colspan="2" class="padding-top:10px;">
						<a href="?page=gf_settings&subview=gravityformswebapi" class="button"><?php esc_html_e( 'Back to API Settings', 'gravityforms' ) ?></a>
					</th>
				</tr>
				</tbody></table>
			<?php
		}

		public function display_api_key_edit( $key_id, $has_updated = false ) {

			$key = $key_id == 0 ? false : $this->get_api_key( $key_id );

			if ( $has_updated ) {?>
				<div class="updated below-h2" style="padding:10px;"><?php esc_html_e( 'API Key successfully updated', 'gravityforms' ); ?></div>
				<?php
			}
			?>

			<table class="form-table gforms_form_settings">
				<tbody><tr id="gaddon-setting-row-public_key">
					<th><?php esc_html_e( 'Description', 'gravityforms' )?></th>
					<td>
						<input type="text" name="key_description" value="<?php echo rgobj( $key, 'description' ); ?>" class="medium gaddon-setting gaddon-text">
					</td>
				</tr>
				<tr>
					<th><?php esc_html_e( 'User', 'gravityforms' )?></th>
					<td>
						<select name="key_user" class="gaddon-setting gaddon-select">
							<?php

							$users = $this->get_users();

							foreach ( $users as $user ) {
								$selected = rgobj( $key, 'user_id' ) == $user['value'] ? ' selected' : '' ?>
								<option value="<?php echo $user['value'] ?>" <?php echo $selected ?>><?php echo $user['label'] ?></option>
								<?php
							}
							?>
						</select>
					</td>
				</tr>
				<tr>
					<th><?php esc_html_e( 'Permission', 'gravityforms' )?></th>
					<td>
						<select name="key_permission" class="gaddon-setting gaddon-select">
							<?php
							$permissions = array(
								array( 'value' => 'read', 'text' => __( 'Read', 'gravityforms' ) ),
								array( 'value' => 'write', 'text' => __( 'Write', 'gravityfroms' ) ),
								array( 'value' => 'read_write', 'text' => __( 'Read/Write', 'gravityforms' ) ),
							);
							foreach ( $permissions as $permission ) {
								$selected = rgobj( $key, 'permissions' ) === $permission['value'] ? ' selected' : '';
								?>
								<option value="<?php echo esc_attr( $permission['value'] ) ?>" <?php echo $selected ?>><?php echo esc_html( $permission['text'] ) ?></option>
								<?php
							}
							?>
						</select>
					</td>
				</tr>
				<?php
				if ( $key_id != 0 ) {
					$last_access = rgobj( $key, 'last_access' ) == '' ? __('Never Accessed', 'gravityforms') : GFCommon::format_date( rgobj( $key, 'last_access' ), true, '', true )
					?>
					<tr>
						<th><?php esc_html_e( 'Key (ending in)', 'gravityforms' )?></th>
						<td>...<?php echo substr( rgobj( $key, 'consumer_key' ), -7 ); ?></td>
					</tr>
					<tr>
						<th style="padding-top:18px;"><?php esc_html_e( 'Last Access', 'gravityforms' )?></th>
						<td style="padding-top:18px;"><?php echo esc_html( $last_access ) ?></td>
					</tr>
					<?php
				}
				$button_label = $key_id == 0 ? __( 'Add Key', 'gravityforms' ) : __( 'Update', 'gravityforms' );
				$link_label = $has_updated ? __( 'Back to API Settings', 'gravityforms' ) : __( 'Cancel', 'gravityforms' );
				?>
				<tr>
					<td colspan="2" style="padding-top:10px;">
						<input type="submit" name="update_key" value="<?php echo $button_label ?>" class="button-primary" style="margin-right:10px; margin-left:10px;">
						<a href="?page=gf_settings&subview=gravityformswebapi" class="button" style="margin-top:10px;"><?php echo esc_html( $link_label ) ?></a>
					</td>

				</tr>
				</tbody></table>
			<?php
		}

		public function plugin_settings_title() {
			return esc_html__( 'Gravity Forms API Settings', 'gravityforms' );
		}

		public function get_users() {
			$args = apply_filters( 'gform_webapi_get_users_settings_page', array( 'number' => 3000 ) );

			$accounts = get_users( $args );

			$account_choices = array();
			foreach ( $accounts as $account ) {
				$account_choices[] = array( 'label' => $account->user_login, 'value' => $account->ID );
			}

			return $account_choices;
		}

		public function plugin_settings_fields() {

			$permalink_structure = get_option( 'permalink_structure' );
			if ( ! $permalink_structure ) {
				return array(
					array(
						'description' => esc_html__( 'The Gravity Forms API allows developers to interact with this install via a JSON REST API.', 'gravityforms' ),
						'fields'      => array(
							array(
								'name'  => 'requirements_check',
								'label' => esc_html__( 'Requirements check', 'gravityforms' ),
								'type'  => 'requirements_check',
							),
							array(
								'id'    => 'save_button',
								'type'  => 'save',
								'value' => esc_attr__( 'Update', 'gravityforms' ),
								'style' => 'display:none;',
							),
						)
					),
				);
			}


			return array(
				array(
					'description' => esc_html__( 'The Gravity Forms API allows developers to interact with this install via a JSON REST API.', 'gravityforms' ),
					'fields'      => array(
						array(
							'type'       => 'checkbox',
							'label'      => esc_html__( 'Enable access to the API', 'gravityforms' ),
							'name'       => 'activate',
							'onclick'    => 'jQuery(this).parents("form").submit();',
							'onkeypress' => 'jQuery(this).parents("form").submit();',
							'choices'    => array(
								array( 'label' => esc_html__( 'Enabled', 'gravityforms' ), 'name' => 'enabled' ),
							)
						),
					),
				),
				array(
					'title'       => esc_html__( 'Authentication ( API version 2 )', 'gravityforms' ),
					'id'          => 'gform_section_authentication_v2',
					'description' => sprintf( __( 'Create an API Key below to use the REST API version 2. Alternatively, you can use cookie authentication which is supported for logged in users. %sVisit our documentation pages%s for more information.', 'gravityforms' ), '<a href="https://docs.gravityforms.com/rest-api-v2/" target="_blank">', '</a>' ),
					'dependency'  => array( $this, 'is_v2_enabled' ),
					'fields'      => array(
						array(
							'type'  => 'api_keys',
							'label' => esc_html__( 'API Keys', 'gravityforms' ),
							'name'  => 'api_keys',
						),
					),
				),
				array(
					'title'       => esc_html__( 'Authentication ( API version 1 )', 'gravityforms' ),
					'id'          => 'gform_section_authentication',
					'description' => sprintf( __( 'Configure your API Key below to use the REST API version 1. Alternatively, you can use cookie authentication which is supported for logged in users. %sVisit our documentation pages%s for more information.', 'gravityforms' ), '<a href="https://docs.gravityforms.com/web-api/" target="_blank">', '</a>' ),
					'dependency'  => array( $this, 'is_v1_enabled' ),
					'fields'      => array(
						array(
							'name'              => 'public_key',
							'label'             => esc_html__( 'Public API Key', 'gravityforms' ),
							'type'              => 'text',
							'default_value'     => substr( wp_hash( site_url() ), 0, 10 ),
							'class'             => 'medium',
							'feedback_callback' => array( $this, 'is_valid_public_key' ),
						),
						array(
							'name'              => 'private_key',
							'label'             => esc_html__( 'Private API Key', 'gravityforms' ),
							'type'              => 'text',
							'default_value'     => substr( wp_hash( get_bloginfo( 'admin_email' ) ), 0, 15 ),
							'class'             => 'medium',
							'feedback_callback' => array( $this, 'is_valid_private_key' )
						),
						array(
							'name'       => 'qrcode',
							'label'      => esc_html__( 'QR Code', 'gravityforms' ),
							'type'       => 'qrcode',
							'dependency' => array( 'field' => 'private_key', 'values' => array( '_notempty_' ) )
						),
						array(
							'name'    => 'impersonate_account',
							'label'   => esc_html__( 'Impersonate account', 'gravityforms' ),
							'type'    => 'select',
							'choices' => $this->get_users(),
						),
					)
				),
				array(
					'fields' => array(
						array(
							'id'    => 'save_button',
							'type'  => 'save',
							'value' => esc_attr__( 'Update', 'gravityforms' ),
						),
					)
				),
			);
		}

		/***
		 * Determines if REST API V1 is enabled.
		 *
		 * @param null $settings Current settings array (optional)
		 *
		 * @return bool True if REST API V1 is enabled, false otherwise
		 */
		public function is_v1_enabled( $settings = null ) {

			$is_api_enabled = $this->get_setting( 'enabled', '', $settings );

			/***
			 * Allows for disabling the REST API V1.
			 *
			 * @since 2.4
			 *
			 * @param bool is_enabled Whether or not REST API V1 is allowed/enabled. Defaults to true.
			 */
			$is_v1_enabled = apply_filters( 'gform_is_rest_api_v1_enabled', true );

			return $is_api_enabled && $is_v1_enabled;
		}

		/***
		 * Determines if REST API V2 is enabled.
		 *
		 * @param null $settings Current settings array (optional)
		 *
		 * @return bool True if REST API V2 is enabled, false otherwise
		 */
		public function is_v2_enabled( $settings = null ) {
			return $this->get_setting( 'enabled', '', $settings ) && ! is_callable( 'gf_rest_api' );
		}

		public function settings_api_keys( $section, $is_first = false ) {

			$table = new GF_API_Keys_Table();
			$table->process_action();
			$table->prepare_items();
			$table->output_styles();
			$table->output_scripts();
			$table->display();
		}

		public function settings_requirements_check() {
			$permalinks_url = admin_url( 'options-permalink.php' );
			?>
			<i class="fa fa-exclamation-triangle gf_invalid"></i>
			<span class="gf_invalid">
					<?php esc_html_e( 'Permalinks are not in the correct format.', 'gravityforms' ); ?>
				</span>
			<br/>
			<span class='gf_settings_description'>
				<?php
				printf( esc_html__( 'Change the %sWordPress Permalink Settings%s from default to any of the other options to get started.', 'gravityforms' ), '<a href="' . esc_url( $permalinks_url ) . '">', '</a>' );
				?>
			</span>
			<?php
		}

		public function settings_qrcode() {
			?>
			<button class="button-secondary"
			        id="gfwebapi-qrbutton"><?php esc_html_e( 'Show/hide QR Code', 'gravityforms' ); ?></button>
			<div id="gfwebapi-qrcode-container" style="display:none;">
				<img id="gfwebapi-qrcode" src="<?php echo GFCommon::get_base_url() ?>/images/spinner.gif"/>
			</div>

			<?php
		}

		public function set_logging_supported( $plugins ) {
			return parent::set_logging_supported( $plugins );
		}

		public function query_vars( $query_vars ) {

			$query_vars[] = GFWEBAPI_ROUTE_VAR;

			return $query_vars;
		}

		public function handle_page_request() {

			global $HTTP_RAW_POST_DATA;

			$route = get_query_var( GFWEBAPI_ROUTE_VAR );
			if ( false == $route ) {
				return;
			}

			send_origin_headers();

			$settings = get_option( 'gravityformsaddon_gravityformswebapi_settings' );
			if ( empty( $settings ) || ! $settings['enabled'] ) {
				$this->log_debug( __METHOD__ . '(): API not enabled, permission denied.' );
				$this->die_permission_denied();
			}

			$route_parts = pathinfo( $route );

			$format = rgar( $route_parts, 'extension' );
			if ( $format ) {
				$route = str_replace( '.' . $format, '', $route );
			}

			$path_array = explode( '/', $route );
			$collection = strtolower( rgar( $path_array, 0 ) );

			$id = rgar( $path_array, 1 );

			if ( strpos( $id, ';' ) !== false ) {
				$id = explode( ';', $id );
			}

			$collection2 = strtolower( rgar( $path_array, 2 ) );
			$id2         = rgar( $path_array, 3 );

			if ( strpos( $id2, ';' ) !== false ) {
				$id2 = explode( ';', $id2 );
			}

			if ( empty( $format ) ) {
				$format = 'json';
			}

			$schema    = strtolower( ( rgget( 'schema' ) ) );
			$offset    = isset( $_GET['paging']['offset'] ) ? strtolower( $_GET['paging']['offset'] ) : 0;
			$page_size = isset( $_GET['paging']['page_size'] ) ? strtolower( $_GET['paging']['page_size'] ) : 10;

			$method = strtoupper( $_SERVER['REQUEST_METHOD'] );
			$args   = compact( 'offset', 'page_size', 'schema' );

			$endpoint = empty( $collection2 ) ? strtolower( $method ) . '_' . $collection : strtolower( $method ) . '_' . $collection . '_' . $collection2;

			// The POST forms/[ID]/submissions endpoint is public and does not require authentication.
			$authentication_required = $endpoint !== 'post_forms_submissions';

			/**
			 * Allows overriding of authentication for all the endpoints of the Web API.
			 * gform_webapi_authentication_required_[end point]
			 * e.g.
			 * gform_webapi_authentication_required_post_form_submissions
			 *
			 * @param bool $authentication_required Whether authentication is required for this endpoint.
			 */
			$authentication_required = apply_filters( 'gform_webapi_authentication_required_' . $endpoint, $authentication_required );

			if ( $authentication_required ) {
				$this->authenticate();
			} else {
				$this->log_debug( __METHOD__ . '(): Authentication not required.' );
			}

			$test_mode = rgget( 'test' );
			if ( $test_mode ) {
				die( 'test mode' );
			}

			if ( empty( $collection2 ) ) {
				do_action( 'gform_webapi_' . $endpoint, $id, $format, $args );
			} else {
				do_action( 'gform_webapi_' . $endpoint, $id, $id2, $format, $args );
			}

			if ( ! isset( $HTTP_RAW_POST_DATA ) ) {
				$HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
			}

			$this->log_debug( __METHOD__ . '(): HTTP_RAW_POST_DATA = ' . $HTTP_RAW_POST_DATA );

			$data = json_decode( $HTTP_RAW_POST_DATA, true );

			switch ( $collection ) {
				case 'forms' :
					switch ( $collection2 ) {
						case 'results' :
							switch ( $method ) {
								case 'GET' :
									$this->get_results( $id );
									break;
								case 'DELETE':
								case 'PUT':
								case 'POST':
								default:
									$this->die_bad_request();
							}
							break;
						case 'properties' :
							switch ( $method ) {
								case 'PUT' :
									$this->put_forms_properties( $data, $id );
									break;
								default:
									$this->die_bad_request();
							}
							break;
						case 'feeds' :
							if ( false == empty( $id2 ) ) {
								$this->die_bad_request();
							}
							switch ( $method ) {
								case 'GET' :
									$this->get_feeds( null, $id );
									break;
								case 'DELETE' :
									$this->delete_feeds( null, $id );
									break;
								case 'PUT' :
									$this->die_not_implemented();
									break;
								case 'POST' :
									$this->post_feeds( $data, $id );
									break;
								default :
									$this->die_bad_request();
							}
							break;
						case 'entries' :
							if ( false == empty( $id2 ) ) {
								$this->die_bad_request();
							}
							switch ( $method ) {
								case 'GET' :
									$this->get_entries( null, $id, $schema );
									break;
								case 'POST' :
									$this->post_entries( $data, $id );
									break;
								case 'PUT' :
								case 'DELETE' :
									$this->die_not_implemented();
									break;
								default:
									$this->die_bad_request();
							}
							break;
						case 'submissions' :
							if ( false == empty( $id2 ) ) {
								$this->die_bad_request();
							}
							switch ( $method ) {
								case 'POST' :
									$this->submit_form( $data, $id );
									break;
								case 'GET' :
								case 'PUT' :
								case 'DELETE' :
									$this->die_not_implemented();
									break;
								default:
									$this->die_bad_request();
							}
							break;
						case '' :
							switch ( $method ) {
								case 'GET':
									$this->get_forms( $id, $schema );
									break;
								case 'DELETE':
									$this->delete_forms( $id );
									break;
								case 'PUT':
									$this->put_forms( $data, $id, $id2 );
									break;
								case 'POST':
									if ( false === empty( $id ) ) {
										$this->die_bad_request();
									}
									$this->post_forms( $data, $id );
									break;
								default:
									$this->die_bad_request();
							}
							break;
						default :
							$this->die_bad_request();
							break;

					}
					break;
				case 'entries' : //  route = /entries/{id}
					switch ( $method ) {
						case 'GET':
							switch ( $collection2 ) {
								case 'fields' : // route = /entries/{id}/fields/{id2}
									$this->get_entries( $id, null, $schema, $id2 );
									break;
								case '' :
									$this->get_entries( $id, null, $schema );
									break;
								default :
									$this->die_bad_request();
							}

							break;
						case 'DELETE' :
							$this->delete_entries( $id );
							break;
						case 'PUT' :
							switch ( $collection2 ) {
								case 'properties' : // route = /entries/{id}/properties/{id2}
									$this->put_entry_properties( $data, $id );
									break;
								case '' :
									$this->put_entries( $data, $id );
									break;
							}

							break;
						case 'POST' :
							if ( false === empty( $id ) ) {
								$this->die_bad_request();
							}
							$this->post_entries( $data );
							break;
						default:
							$this->die_bad_request();
					}
					break;
				case 'feeds' :
					switch ( $method ) {
						case 'GET' :
							$this->get_feeds( $id );
							break;
						case 'DELETE' :
							if ( empty( $id ) ) {
								$this->die_bad_request();
							}
							$this->delete_feeds( $id );
							break;
						case 'PUT' :
							$this->put_feeds( $data, $id );
							break;
						case 'POST' :
							if ( false === empty( $id ) ) {
								$this->die_bad_request();
							}
							$this->post_feeds( $data );
							break;
						default :
							$this->die_bad_request();
					}
					break;
				default :
					$this->die_bad_request();
					break;
			}


			$this->die_bad_request();

		}

		public function authorize( $caps = array() ) {

			if ( GFCommon::current_user_can_any( $caps ) ) {

				GFCommon::add_api_call();

				return true;
			}

			$this->die_forbidden();
		}

		public function ajax_delete_key() {

			$key_id = rgpost( 'key' );
			$this->delete_api_key( $key_id );
			die( 0 );
		}

		public static function get_api_keys() {
			global $wpdb;
			$table_name = GFFormsModel::get_rest_api_keys_table_name();

			$keys  = $wpdb->get_results("
			SELECT key_id, user_id, description, permissions, concat('...', substring( consumer_key, -7, 7 )) as 'key', u.user_login as user, last_access
			FROM {$table_name} k
			INNER JOIN {$wpdb->prefix}users u ON k.user_id = u.id
		", ARRAY_A
			);

			return $keys;
		}

		public function get_api_key( $key_id ) {
			global $wpdb;
			$table_name = GFFormsModel::get_rest_api_keys_table_name();

			$key  = $wpdb->get_row( $wpdb->prepare("
						SELECT *
						FROM {$table_name}
						WHERE key_id=%d", $key_id ) );

			return $key;
		}

		public function delete_api_key( $key_id ) {
			global $wpdb;
			$table_name = GFFormsModel::get_rest_api_keys_table_name();

			$wpdb->query(
				$wpdb->prepare("
				DELETE FROM {$table_name}
				WHERE key_id=%d
		", $key_id
				)
			);
		}

		public function update_api_key( $key_id, $key ) {
			global $wpdb;

			if ( $key_id == 0 ) {
				$consumer_key    = 'ck_' . $this->rand_hash();
				$consumer_secret = 'cs_' . $this->rand_hash();

				$key['consumer_key']    = self::api_hash( $consumer_key );
				$key['consumer_secret'] = $consumer_secret;
				$key['truncated_key'] = substr( $consumer_key, -7 );

				$wpdb->insert(
					GFFormsModel::get_rest_api_keys_table_name(),
					$key
				);

				return array( 'consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret );

			} else {

				unset( $key['last_access'] );
				unset( $key['consumer_key'] );
				unset( $key['consumer_secret'] );
				unset( $key['truncated_key'] );

				$wpdb->update( GFFormsModel::get_rest_api_keys_table_name(), $key, array( 'key_id' => $key_id ) );

				return array( 'consumer_key' => '', 'consumer_secret' => '' );
			}
		}


		//----- Feeds ------

		public function get_feeds( $feed_ids, $form_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to get feeds via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_get_feeds', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			$addon_slug = rgget( 'addon' );
			$output     = GFAPI::get_feeds( $feed_ids, $form_id, $addon_slug );
			if ( is_wp_error( $output ) ) {
				$this->die_not_found();
			}

			$response = false === empty( $feed_ids ) && false === is_array( $feed_ids ) && is_array( $output ) ? array_shift( $output ) : '';

			$this->end( 200, $response );

		}

		public function delete_feeds( $feed_ids, $form_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to delete feeds via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_delete_feeds', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			$count = 0;
			if ( empty( $feed_ids ) ) {
				$feeds = GFAPI::get_feeds( null, $form_id );
				foreach ( $feeds as $feed ) {
					$result = GFAPI::delete_feed( $feed['id'] );
					if ( is_wp_error( $result ) ) {
						break;
					}
					$count ++;
				}
			} else {
				if ( is_array( $feed_ids ) ) {
					foreach ( $feed_ids as $feed_id ) {
						$result = GFAPI::delete_feed( $feed_id );
						if ( is_wp_error( $result ) ) {
							break;
						}
						$count ++;
					}
				} else {
					$result = GFAPI::delete_feed( $feed_ids );
					$count ++;
				}
			}

			if ( isset( $result ) && is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = sprintf( __( 'Feeds deleted successfully: %d', 'gravityforms' ), $count );
			}

			$this->end( $status, $response );
		}

		public function put_feeds( $feed_data, $feed_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to update feeds via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_put_feeds', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			$count  = 0;
			$result = array();
			if ( empty( $feed_id ) ) {
				foreach ( $feed_data as $feed ) {
					//todo: validate feed id and form id
					$result = GFAPI::update_feed( $feed['id'], $feed['meta'], $feed['form_id'] );
					if ( is_wp_error( $result ) ) {
						break;
					}
					$count ++;
				}
			} else {
				$result = GFAPI::update_feed( $feed_id, $feed_data['meta'], $feed_data['form_id'] );
				$count ++;
			}


			if ( isset( $results ) && is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = sprintf( __( 'Feeds updated: %d', 'gravityforms' ), $count );
			}

			$this->end( $status, $response );
		}

		public function post_feeds( $feeds, $form_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to create feeds via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_post_feeds', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			$feed_ids = array();
			$result   = array();
			foreach ( $feeds as $feed ) {
				$addon_slug = isset( $feed['addon_slug'] ) ? $feed['addon_slug'] : rgget( 'addon' );
				$f_id       = empty( $form_id ) ? $feed['form_id'] : $form_id;
				if ( empty( $f_id ) ) {
					$result = new WP_Error( 'missing_form_id', __( 'Missing form id', 'gravityforms' ) );
					break;
				}
				$result = GFAPI::add_feed( $f_id, $feed['meta'], $addon_slug );
				if ( is_wp_error( $result ) ) {
					break;
				}
				$feed_ids[] = $result;
			}
			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 201;
				$response = $feed_ids;

			}

			$this->end( $status, $response );
		}

		//----- Form Submissions ----

		public function submit_form( $data, $id ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			$form_id = absint( $id );

			if ( $form_id < 1 ) {
				$this->die_bad_request();
			}

			if ( empty( $data['input_values'] ) ) {
				$this->die_bad_request();
			}

			$field_values = isset( $data['field_values'] ) ? $data['field_values'] : array();
			$target_page  = isset( $data['target_page'] ) ? $data['target_page'] : 0;
			$source_page  = isset( $data['source_page'] ) ? $data['source_page'] : 1;

			add_filter( 'gform_require_login', '__return_false' );

			$result = GFAPI::submit_form( $form_id, $data['input_values'], $field_values, $target_page, $source_page );

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				if ( ! $this->current_user_can_any( array(
					'gravityforms_view_entries',
					'gravityforms_edit_entries',
				) ) ) {
					unset( $result['entry_id'] );
				}

				$status   = 200;
				$response = $result;
			}

			$this->end( $status, $response );
		}

		//----- Forms ------

		public function delete_forms( $form_ids ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to delete forms via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_delete_forms', 'gravityforms_delete_forms' );
			$this->authorize( $capability );

			$count = 0;
			if ( is_array( $form_ids ) ) {
				foreach ( $form_ids as $form_id ) {
					$result = GFAPI::delete_form( $form_id );
					if ( is_wp_error( $result ) ) {
						break;
					}
					$count ++;
				}
			} else {
				$result = GFAPI::delete_form( $form_ids );
				$count ++;
			}

			if ( isset( $result ) && is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = sprintf( __( 'Forms deleted successfully: %d', 'gravityforms' ), $count );

			}

			$this->end( $status, $response );
		}

		public function post_entries( $data, $form_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to create entries via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_post_entries', 'gravityforms_edit_entries' );
			$this->authorize( $capability );

			$entries = array();
			foreach ( $data as $entry ) {
				$entries[] = $this->maybe_serialize_list_fields( $entry, $form_id );
			}

			$result = GFAPI::add_entries( $entries, $form_id );

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 201;
				$response = $result;
			}

			$this->end( $status, $response );
		}

		public function put_entries( $data, $entry_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to update entries via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_put_entries', 'gravityforms_edit_entries' );
			$this->authorize( $capability );
			$entries = array();
			if ( empty( $entry_id ) ) {
				foreach ( $data as $entry ) {
					$entries[] = $this->maybe_serialize_list_fields( $entry );
				}
				$result = GFAPI::update_entries( $entries );
			} else {
				$entry  = $this->maybe_serialize_list_fields( $data );
				$result = GFAPI::update_entry( $entry, $entry_id );
			}

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = empty( $entry_id ) ? __( 'Entries updated successfully', 'gravityforms' ) : __( 'Entry updated successfully', 'gravityforms' );
			}

			$this->end( $status, $response );
		}

		public function put_forms_properties( $property_values, $form_id ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to update form properties via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_put_forms_properties', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			foreach ( $property_values as $key => $property_value ) {
				$result = GFAPI::update_form_property( $form_id, $key, $property_value );
				if ( is_wp_error( $result ) ) {
					break;
				}
			}

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = __( 'Success', 'gravityforms' );
			}

			$this->end( $status, $response );

		}

		public function put_entry_properties( $property_values, $entry_id ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to update entry properties via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_put_entries_properties', 'gravityforms_edit_entries' );
			$this->authorize( $capability );

			if ( is_array( $property_values ) ) {
				foreach ( $property_values as $key => $property_value ) {
					$result = GFAPI::update_entry_property( $entry_id, $key, $property_value );
					if ( is_wp_error( $result ) ) {
						break;
					}
				}

				if ( is_wp_error( $result ) ) {
					$response = $this->get_error_response( $result );
					$status   = $this->get_error_status( $result );
				} else {
					$status   = 200;
					$response = __( 'Success', 'gravityforms' );
				}
			} else {
				$status = 400;
				if ( empty( $property_values ) ) {
					$response = __( 'No property values were found in the request body', 'gravityforms' );
				} else {
					$response = __( 'Property values should be sent as an array', 'gravityforms' );
				}
			}

			$this->end( $status, $response );

		}

		public function post_forms( $data ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to create forms via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_post_forms', 'gravityforms_create_form' );
			$this->authorize( $capability );

			$form_ids = GFAPI::add_forms( $data );

			if ( is_wp_error( $form_ids ) || count( $form_ids ) == 0 ) {
				$response = $this->get_error_response( $form_ids );
				$status   = $this->get_error_status( $form_ids );
			} else {
				$status   = 201;
				$response = $form_ids;
			}

			$this->end( $status, $response );
		}

		public function put_forms( $data, $form_id = null ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to update forms via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_put_forms', 'gravityforms_create_form' );
			$this->authorize( $capability );

			if ( empty( $form_id ) ) {
				$result = GFAPI::update_forms( $data );
			} else {
				$result = GFAPI::update_form( $data, $form_id );
			}

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = empty( $form_id ) ? __( 'Forms updated successfully', 'gravityforms' ) : __( 'Form updated successfully', 'gravityforms' );
			}

			$this->end( $status, $response );
		}

		public function delete_entries( $entry_ids ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to delete entries via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_delete_entries', 'gravityforms_delete_entries' );
			$this->authorize( $capability );

			$count = 0;
			if ( is_array( $entry_ids ) ) {
				foreach ( $entry_ids as $entry_id ) {
					$this->log_debug( __METHOD__ . '(): Deleting entry id ' . $entry_id );
					$result = GFAPI::delete_entry( $entry_id );
					if ( is_wp_error( $result ) ) {
						break;
					}
					$count ++;
				}
			} else {
				$result = GFAPI::delete_entry( $entry_ids );
				$count ++;
			}

			if ( isset( $result ) && is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			} else {
				$status   = 200;
				$response = sprintf( __( 'Entries deleted successfully: %d', 'gravityforms' ), $count );
			}

			$this->end( $status, $response );
		}

		public function get_entries( $entry_ids, $form_ids = null, $schema = '', $field_ids = array() ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to get entries via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_get_entries', 'gravityforms_view_entries' );
			$this->authorize( $capability );

			$status   = 200;
			$response = array();
			$result   = array();
			if ( $entry_ids ) {

				if ( is_array( $entry_ids ) ) {
					foreach ( $entry_ids as $entry_id ) {
						$result = GFAPI::get_entry( $entry_id );
						if ( ! is_wp_error( $result ) ) {
							$result                = $this->maybe_json_encode_list_fields( $result );
							$response[ $entry_id ] = $result;
							if ( ! empty( $field_ids ) && ( ! empty( $response[ $entry_id ] ) ) ) {
								$response[ $entry_id ] = $this->filter_entry_object( $response[ $entry_id ], $field_ids );
							}
						}
					}
				} else {
					$result = GFAPI::get_entry( $entry_ids );
					if ( ! is_wp_error( $result ) ) {
						$result   = $this->maybe_json_encode_list_fields( $result );
						$response = $result;
						if ( ! empty( $field_ids ) && ( ! empty( $response ) ) ) {
							$response = $this->filter_entry_object( $response, $field_ids );
						}
					}
				}

				if ( $schema == 'mtd' ) {
					$response = self::mtd_transform_entry_data( $response );
				}
			} else {

				// Sorting parameters
				$sort_key = isset( $_GET['sorting']['key'] ) && ! empty( $_GET['sorting']['key'] ) ? $_GET['sorting']['key'] : 'id';
				$sort_dir = isset( $_GET['sorting']['direction'] ) && ! empty( $_GET['sorting']['direction'] ) ? $_GET['sorting']['direction'] : 'DESC';
				$sorting  = array( 'key' => $sort_key, 'direction' => $sort_dir );
				if ( isset( $_GET['sorting']['is_numeric'] ) ) {
					$sorting['is_numeric'] = $_GET['sorting']['is_numeric'];
				}

				// Paging parameters
				$page_size = isset( $_GET['paging']['page_size'] ) ? intval( $_GET['paging']['page_size'] ) : 10;
				if ( isset( $_GET['paging']['current_page'] ) ) {
					$current_page = intval( $_GET['paging']['current_page'] );
					$offset       = $page_size * ( $current_page - 1 );
				} else {
					$offset = isset( $_GET['paging']['offset'] ) ? intval( $_GET['paging']['offset'] ) : 0;
				}

				$paging = array( 'offset' => $offset, 'page_size' => $page_size );

				if ( isset( $_GET['search'] ) ) {
					$search = $_GET['search'];
					if ( ! is_array( $search ) ) {
						$search = urldecode( ( stripslashes( $search ) ) );
						$search = json_decode( $search, true );
					}
				} else {
					$search = array();
				}

				if ( empty( $form_ids ) ) {
					$form_ids = 0;
				} // all forms

				$entry_count = GFAPI::count_entries( $form_ids, $search );

				$result = $entry_count > 0 ? GFAPI::get_entries( $form_ids, $search, $sorting, $paging ) : array();

				if ( ! is_wp_error( $result ) ) {
					foreach ( $result as &$entry ) {
						$entry = $this->maybe_json_encode_list_fields( $entry );
					}
					$response = array( 'total_count' => $entry_count, 'entries' => $result );

					if ( $schema == 'mtd' ) {
						$response = $this->mtd_transform_entries_data( $response, $form_ids );
					}
				}
			}

			if ( is_wp_error( $result ) ) {
				$response = $this->get_error_response( $result );
				$status   = $this->get_error_status( $result );
			}

			$this->end( $status, $response );
		}

		public static function filter_entry_object( $entry, $field_ids ) {

			if ( ! is_array( $field_ids ) ) {
				$field_ids = array( $field_ids );
			}
			$new_entry = array();
			foreach ( $entry as $key => $val ) {
				if ( in_array( $key, $field_ids ) || ( is_numeric( $key ) && in_array( intval( $key ), $field_ids ) ) ) {
					$new_entry[ $key ] = $val;
				}
			}

			return $new_entry;
		}

		public function get_forms( $form_ids = null, $schema = '' ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to get form details via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_get_forms', 'gravityforms_edit_forms' );
			$this->authorize( $capability );

			$status   = 200;
			$response = array();
			if ( empty( $form_ids ) ) {
				$forms = RGFormsModel::get_forms( true );
				foreach ( $forms as $form ) {
					$form_id              = $form->id;
					$totals               = GFFormsModel::get_form_counts( $form_id );
					$form_info            = array(
						'id'      => $form_id,
						'title'   => $form->title,
						'entries' => rgar( $totals, 'total' )
					);
					$response[ $form_id ] = $form_info;
				}
				if ( $schema == 'mtd' ) {
					$response = $this->mtd_transform_forms_data( $response );
				}
			} else {
				if ( is_array( $form_ids ) ) {
					foreach ( $form_ids as $form_id ) {
						$response[ $form_id ] = GFAPI::get_form( $form_id );
					}
				} else {
					$result = GFAPI::get_form( $form_ids );
					if ( is_wp_error( $result ) ) {
						$response = $this->get_error_response( $result );
						$status   = $this->get_error_status( $result );
					} elseif ( ! $result ) {
						$this->die_not_found();
					} else {
						$response = $result;
					}
				}
			}

			$this->end( $status, $response );
		}

		public function maybe_json_encode_list_fields( $entry ) {
			$form_id = $entry['form_id'];
			$form    = GFAPI::get_form( $form_id );
			if ( ! empty ( $form['fields'] ) && is_array( $form['fields'] ) ) {
				foreach ( $form['fields'] as $field ) {
					/* @var GF_Field $field */
					if ( $field->get_input_type() == 'list' ) {
						$new_value = maybe_unserialize( $entry[ $field->id ] );

						if ( ! $this->is_json( $new_value ) ) {
							$new_value = json_encode( $new_value );
						}

						$entry[ $field->id ] = $new_value;
					}
				}
			}

			return $entry;
		}

		public function maybe_serialize_list_fields( $entry, $form_id = null ) {
			if ( empty( $form_id ) ) {
				$form_id = $entry['form_id'];
			}
			$form = GFAPI::get_form( $form_id );
			if ( ! empty ( $form['fields'] ) && is_array( $form['fields'] ) ) {
				foreach ( $form['fields'] as $field ) {
					/* @var GF_Field $field */
					if ( $field->get_input_type() == 'list' ) {
						$new_list_value = $this->maybe_decode_json( $entry[ $field->id ] );
						if ( ! is_serialized( $new_list_value ) ) {
							$new_list_value = serialize( $new_list_value );
						}
						$entry[ $field->id ] = $new_list_value;
					}
				}
			}

			return $entry;
		}


		// RESULTS

		public function get_results_cache_key( $form_id, $fields, $search_criteria ) {

			$key = $this->get_results_cache_key_prefix( $form_id );
			$key .= wp_hash( json_encode( $fields ) . json_encode( $search_criteria ) );

			return $key;
		}

		public function get_results_cache_key_prefix( $form_id ) {
			global $blog_id;

			$key = is_multisite() ? $blog_id . '-' : '';

			$key .= sprintf( '%s-cache-%s-', $this->_slug, $form_id );

			// The option_name column in the options table has a max length of 64 chars.
			// Truncate the key if it's too long for column and allow space for the 'tmp' prefix
			$key = substr( $key, 0, 60 );

			return $key;
		}

		public function update_entry_status( $lead_id ) {
			$lead    = RGFormsModel::get_lead( $lead_id );
			$form_id = $lead['form_id'];
			$form    = GFFormsModel::get_form_meta( $form_id );
			$this->maybe_update_results_cache_meta( $form );
		}

		public function entry_updated( $form, $lead_id ) {
			$this->maybe_update_results_cache_meta( $form );
		}

		public function entry_created( $entry, $form ) {
			$this->maybe_update_results_cache_meta( $form );
		}

		public function after_save_form( $form, $is_new ) {
			if ( $is_new ) {
				return;
			}
			$form_id = $form['id'];

			// only need cache meta when a cache exists
			if ( false === $this->results_cache_exists( $form_id ) ) {
				return;
			}

			$fields              = rgar( $form, 'fields' );
			$current_fields_hash = wp_hash( json_encode( $fields ) );

			$cache_meta         = $this->get_results_cache_meta( $form_id );
			$cached_fields_hash = rgar( $cache_meta, 'fields_hash' );

			if ( $current_fields_hash !== $cached_fields_hash ) {
				// delete the meta for this form
				$this->delete_results_cache_meta( $form_id );
				// delete all cached results for this form
				$this->delete_cached_results( $form_id );
			}
		}

		public function results_cache_exists( $form_id ) {
			global $wpdb;

			$key = $this->get_results_cache_key_prefix( $form_id );

			$key = '%' . GFCommon::esc_like( $key ) . '%';

			$sql = $wpdb->prepare( "SELECT count(option_id) FROM $wpdb->options WHERE option_name LIKE %s", $key );

			$result = $wpdb->get_var( $sql );

			return $result > 0;

		}

		public function delete_cached_results( $form_id ) {
			global $wpdb;

			$form = GFAPI::get_form( $form_id );
			if ( ! ( $form ) || ! is_array( $form ) ) {
				return;
			}

			$key = $this->get_results_cache_key_prefix( $form_id );

			$key = '%' . GFCommon::esc_like( $key ) . '%';

			$sql = $wpdb->prepare( "DELETE FROM $wpdb->options WHERE option_name LIKE %s", $key );

			$result = $wpdb->query( $sql );

			return $result;
		}

		// When entries are added or updated the cache needs to be expired and rebuilt.
		// This cache meta records the last updated time for each form and a hash of the fields array.
		// Each time results are requested this value is checked to make sure the cache is still valid.
		public function maybe_update_results_cache_meta( $form ) {
			$form_id = $form['id'];

			// only need to expire the cache when a cache already exists
			if ( false === $this->results_cache_exists( $form_id ) ) {
				return;
			}

			$this->update_results_cache_meta( $form_id, rgar( $form, 'fields' ) );
		}

		public function update_results_cache_meta( $form_id, $fields, $expiry = null ) {

			if ( empty( $expiry ) ) {
				$expiry = time();
			}

			$data = array(
				'fields_hash' => wp_hash( json_encode( $fields ) ),
				'timestamp'   => $expiry,
			);

			$key = $this->get_results_cache_meta_key( $form_id );

			$this->update_results_cache( $key, $data );

		}

		public function delete_results_cache_meta( $form_id ) {

			$key = $this->get_results_cache_meta_key( $form_id );

			delete_option( $key );

		}

		public function get_results_cache_meta_key( $form_id ) {
			global $blog_id;

			$key = is_multisite() ? $blog_id . '-' : '';
			$key .= 'gfresults-cache-meta-form-' . $form_id;

			return $key;
		}

		public function get_results_cache_meta( $form_id ) {

			$key        = $this->get_results_cache_meta_key( $form_id );
			$cache_meta = get_option( $key );

			return $cache_meta;
		}

		public function update_results_cache( $key, $data ) {

			delete_option( $key );

			$result = add_option( $key, $data, '', 'no' );

			return $result;
		}

		// Recursive wp_cron task to continue the calculation of results
		public function results_cron( $form, $fields, $search_criteria ) {

			$form_id = $form['id'];
			$key     = $this->get_results_cache_key( $form_id, $fields, $search_criteria );
			$key_tmp = 'tmp' . $key;
			$state   = get_option( $key_tmp, array() );

			if ( ! empty( $state ) ) {
				if ( ! class_exists( 'GFResults' ) ) {
					require_once( GFCommon::get_base_path() . '/includes/addon/class-gf-results.php' );
				}
				$gf_results = new GFResults( $this->_slug, array() );
				$results    = $gf_results->get_results_data( $form, $fields, $search_criteria, $state );
				if ( 'complete' == $results['status'] ) {
					if ( isset( $results['progress'] ) ) {
						unset( $results['progress'] );
					}
					$this->update_results_cache( $key, $results );
					if ( false == empty( $state ) ) {
						delete_option( $key_tmp );
					}
				} else {
					$this->update_results_cache( $key_tmp, $results );

					$data = get_option( $key );
					if ( $data ) {
						$data['progress'] = $results['progress'];
						$this->update_results_cache( $key, $data );
					}

					$this->schedule_results_cron( $form, $fields, $search_criteria );
				}
			}
		}

		// Returns an array with the results for all the fields in the form.
		// If the results can be calculated within the time allowed in GFResults then the results are returned and nothing is cached.
		// If the calculation has not finished then a single recursive wp_cron task will be scheduled for immediate execution.
		// While the cache is being built by the wp_cron task this function will return the expired cache results if available or the latest step in the cache build.
		// Add-On-specific results are not included e.g. grade frequencies in the Quiz Add-On.
		public function get_results( $form_id ) {
			$this->log_debug( __METHOD__ . '(): Running.' );

			/**
			 * Filters the capability required to get form results via the web API.
			 *
			 * @since 1.9.2
			 */
			$capability = apply_filters( 'gform_web_api_capability_get_results', 'gravityforms_view_entries' );
			$this->authorize( $capability );

			$s = rgget( 's' ); // search criteria

			$search_criteria = false === empty( $s ) && is_array( $s ) ? $s : array();

			$form = GFAPI::get_form( $form_id );

			if ( ! $form ) {
				self::die_not_found();
			}

			// for the Web API return all fields
			$fields = rgar( $form, 'fields' );

			$form_id = $form['id'];
			$key     = $this->get_results_cache_key( $form_id, $fields, $search_criteria );
			$key_tmp = 'tmp' . $key;

			$data = get_option( $key, array() );

			$cache_meta = $this->get_results_cache_meta( $form_id );

			// add the cache meta early so form editor updates can test for valid field hash
			if ( empty( $cache_meta ) ) {
				$this->update_results_cache_meta( $form_id, $fields, 0 );
			}

			$cache_expiry    = rgar( $cache_meta, 'timestamp' );
			$cache_timestamp = isset( $data['timestamp'] ) ? $data['timestamp'] : 0;
			$cache_expired   = $cache_expiry ? $cache_expiry > $cache_timestamp : false;

			// check for valid cached results first
			if ( ! empty( $data ) && 'complete' == rgar( $data, 'status' ) && ! $cache_expired ) {
				$results = $data;
				$status  = 200;
				if ( isset( $results['progress'] ) ) {
					unset( $results['progress'] );
				}
			} else {

				$state = get_option( $key_tmp );

				if ( empty( $state ) || ( 'complete' == rgar( $data, 'status' ) && $cache_expired ) ) {
					if ( ! class_exists( 'GFResults' ) ) {
						require_once( GFCommon::get_base_path() . '/includes/addon/class-gf-results.php' );
					}
					$gf_results         = new GFResults( $this->_slug, array() );
					$max_execution_time = 5;
					$results            = $gf_results->get_results_data( $form, $fields, $search_criteria, $state, $max_execution_time );
					if ( 'complete' == rgar( $data, 'status' ) ) {
						$status = 200;
						if ( false == empty( $state ) ) {
							delete_option( $key_tmp );
						}
					} else {

						if ( false === empty( $data ) && 'complete' == rgar( $data, 'status' ) && $cache_expired ) {
							$data['status']   = 'expired';
							$data['progress'] = $results['progress'];
							$this->update_results_cache( $key, $data );
						}

						$this->update_results_cache( $key_tmp, $results );

						$this->schedule_results_cron( $form, $fields, $search_criteria );

						if ( $data ) {
							$results = $data;
						}

						$status = 202;
					}
				} else {

					// The cron task is recursive, not periodic, so system restarts, script timeouts and memory issues can prevent the cron from restarting.
					// Check timestamp and kick off the cron again if it appears to have stopped
					$state_timestamp = rgar( $state, 'timestamp' );
					$state_age       = time() - $state_timestamp;
					if ( $state_age > 180 && ! $this->results_cron_is_scheduled( $form, $fields, $search_criteria ) ) {
						$this->schedule_results_cron( $form, $fields, $search_criteria );
					}

					if ( false === empty( $data ) && 'expired' == rgar( $data, 'status' ) ) {
						$results = $data;
					} else {
						$results = $state;
					}
					$status = 202;
				}
			}

			$fields = rgar( $results, 'field_data' );

			if ( ! empty( $fields ) ) {
				// add choice labels to the results so the client doesn't need to cross-reference with the form object
				$results['field_data'] = $this->results_data_add_labels( $form, $fields );
			}


			$this->end( $status, $results );
		}

		public function schedule_results_cron( $form, $fields, $search_criteria, $delay_in_seconds = 10 ) {
			// reduces problems with concurrency
			wp_cache_delete( 'alloptions', 'options' );

			$args = array( $form, $fields, $search_criteria );

			wp_schedule_single_event( time() + $delay_in_seconds, $this->get_results_cron_hook(), $args );
		}

		public function results_cron_is_scheduled( $form, $fields, $search_criteria ) {
			$args = array( $form, $fields, $search_criteria );

			return wp_next_scheduled( $this->get_results_cron_hook(), $args );
		}

		public function get_results_cron_hook() {
			return 'gravityforms_results_cron_' . $this->_slug;
		}

		public function results_data_add_labels( $form, $fields ) {

			// replace the values/ids with text labels
			foreach ( $fields as $field_id => $choice_counts ) {
				$field = GFFormsModel::get_field( $form, $field_id );
				$type  = $field->get_input_type();
				if ( is_array( $choice_counts ) ) {
					$i = 0;
					foreach ( $choice_counts as $choice_value => $choice_count ) {
						if ( class_exists( 'GFSurvey' ) && 'likert' == $type && rgar( $field, 'gsurveyLikertEnableMultipleRows' ) ) {
							$row_text       = GFSurvey::get_likert_row_text( $field, $i ++ );
							$counts_for_row = array();
							foreach ( $choice_count as $col_val => $col_count ) {
								$text                       = GFSurvey::get_likert_column_text( $field, $choice_value . ':' . $col_val );
								$counts_for_row[ $col_val ] = array( 'text' => $text, 'data' => $col_count );
							}
							$counts_for_row[ $choice_value ]['data'] = $counts_for_row;
							$fields[ $field_id ][ $choice_value ]    = array(
								'text'  => $row_text,
								'value' => "$choice_value",
								'count' => $counts_for_row
							);

						} else {
							$text                                 = GFFormsModel::get_choice_text( $field, $choice_value );
							$fields[ $field_id ][ $choice_value ] = array(
								'text'  => $text,
								'value' => "$choice_value",
								'count' => $choice_count
							);
						}
					}
				}
			}

			return $fields;
		}

		// ----- end RESULTS


		private function authenticate() {
			$this->log_debug( __METHOD__ . '(): Running.' );

			if ( isset( $_REQUEST['_gf_json_nonce'] ) && is_user_logged_in() ) {
				$this->log_debug( __METHOD__ . '(): Using WP cookie authentication.' );
				// WordPress cookie authentication for plugins and themes on this server.
				check_admin_referer( 'gf_api', '_gf_json_nonce' );

				return true;
			}

			$authenticated = false;

			if ( isset( $_GET['api_key'] ) ) {
				$this->log_debug( __METHOD__ . '(): API Key found in request.' );

				// Signatures required for external requests
				if ( rgget( 'api_key' ) == $this->_public_key ) {
					if ( self::check_signature() ) {
						$authenticated = true;
					}
				}
			}

			if ( $authenticated ) {
				$settings = get_option( 'gravityformsaddon_gravityformswebapi_settings' );
				if ( empty( $settings ) || ! $settings['enabled'] ) {
					$authenticated = false;
				} else {
					$this->log_debug( __METHOD__ . '(): Switching to impersonation account.' );
					$account_id = $settings['impersonate_account'];
					wp_set_current_user( $account_id );
				}
			}

			if ( ! $authenticated ) {
				$this->log_debug( __METHOD__ . '(): Could not authenticate, permission denied.' );
				$this->die_permission_denied();
			}
		}

		private function check_signature() {
			if ( false === GFWEBAPI_REQUIRE_SIGNATURE ) {
				return true;
			}

			$this->log_debug( __METHOD__ . '(): Running.' );

			$expires = (int) rgget( 'expires' );

			$api_key = rgget( 'api_key' );
			$path    = strtolower( get_query_var( GFWEBAPI_ROUTE_VAR ) );
			$method  = strtoupper( $_SERVER['REQUEST_METHOD'] );

			$signature = rgget( 'signature' );

			$string_to_check = sprintf( '%s:%s:%s:%s', $api_key, $method, $path, $expires );

			$calculated_sig = $this->calculate_signature( $string_to_check );

			if ( time() >= $expires ) {
				$this->log_debug( __METHOD__ . '(): result = expired.' );

				return false;
			}

			$is_valid = $signature == $calculated_sig || $signature == rawurlencode( $calculated_sig );
			$this->log_debug( __METHOD__ . '(): result = ' . var_export( $is_valid, 1 ) );

			return $is_valid;
		}

		private function calculate_signature( $string ) {
			$hash = hash_hmac( 'sha1', $string, $this->_private_key, true );
			$sig  = base64_encode( $hash );

			return $sig;
		}

		public static function end( $status, $response ) {
			$output['status']   = $status;
			$output['response'] = $response;

			// PHP > 5.3
			if ( function_exists( 'header_remove' ) && ! headers_sent() ) {
				header_remove( 'X-Pingback' );
			}

			header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ), true );
			$output_json = json_encode( $output );

			echo $output_json;
			die();
		}

		public function die_not_authorized() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 401, __( 'Not authorized', 'gravityforms' ) );
		}

		public function die_permission_denied() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 401, __( 'Permission denied', 'gravityforms' ) );
		}

		public function die_forbidden() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 403, __( 'Forbidden', 'gravityforms' ) );
		}

		public function die_bad_request() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 400, __( 'Bad request', 'gravityforms' ) );
		}

		public function die_not_found() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 404, __( 'Not found', 'gravityforms' ) );
		}

		public function die_not_implemented() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 501, __( 'Not implemented', 'gravityforms' ) );
		}

		public function die_error() {
			$this->log_debug( __METHOD__ . '(): Running.' );
			$this->end( 500, __( 'Internal Error', 'gravityforms' ) );
		}

		public function get_error_response( $wp_error ) {
			$response['code']    = $wp_error->get_error_code();
			$response['message'] = $wp_error->get_error_message();
			$data                = $wp_error->get_error_data();
			if ( $data ) {
				$response['data'] = $data;
			}

			return $response;
		}

		public function get_error_status( $wp_error ) {
			$error_code = $wp_error->get_error_code();
			$mappings   = array(
				'not_found'   => 404,
				'not_allowed' => 401,
			);
			$http_code  = isset( $mappings[ $error_code ] ) ? $mappings[ $error_code ] : 400;

			return $http_code;
		}

		public static function get_form_metas() {
			$form_ids = array();
			$forms    = RGFormsModel::get_forms( true );
			foreach ( $forms as $form ) {
				$form_ids[] = $form->id;
			}
			$form_metas = GFFormsModel::get_form_meta_by_id( $form_ids );

			return $form_metas;
		}

		public static function ajax_qrcode() {
			require_once GFCommon::get_base_path() . '/includes/phpqrcode/phpqrcode.php';
			$settings = get_option( 'gravityformsaddon_gravityformswebapi_settings' );
			if ( empty( $settings ) ) {
				die();
			}

			if ( ! GFAPI::current_user_can_any( 'gravityforms_api_settings' ) ) {
				die();
			}

			$data['url']         = site_url();
			$data['name']        = get_bloginfo();
			$data['public_key']  = rgar( $settings, 'public_key' );
			$data['private_key'] = rgar( $settings, 'private_key' );

			QRcode::png( json_encode( $data ), false, QR_ECLEVEL_L, 4, 1, false );
			die();
		}

		/**
		 * Support for MonoTouch.Dialog
		 */
		// todo: support array of form ids
		public function mtd_transform_entries_data( $output, $form_id ) {
			$form                  = GFFormsModel::get_form_meta( $form_id );
			$form_element          = array();
			$form_element['title'] = $form['title'];
			$form_element['type']  = 'root';
			$form_element['id']    = 'id-form-' . $form_id;
			$form_element['count'] = rgar( $output, 'total_count' );
			$entries               = rgar( $output, 'entries' );

			$section['header'] = 'Entries';
			$entry_elements    = array();
			if ( is_array( $entries ) ) {
				foreach ( $entries as $entry ) {
					$entry_element['type']  = 'root';
					$entry_element['title'] = $entry['id'] . ': ' . $entry['date_created'];
					$entry_element['id']    = $entry['id'];
					$entry_element['url']   = GFWEBAPI_API_BASE_URL . '/entries/' . rgar( $entry, 'id' ) . '?schema=mtd';
					$entry_elements[]       = $entry_element;
				}
			}

			$section['elements']        = $entry_elements;
			$form_element['sections'][] = $section;

			return $form_element;
		}

		public function mtd_transform_forms_data( $forms ) {
			$data          = array();
			$data['title'] = 'Forms';
			$data['type']  = 'root';
			$data['id']    = 'forms';

			foreach ( $forms as $form ) {
				$element               = array();
				$element['title']      = $form['title'];
				$element['type']       = 'root';
				$element['id']         = 'id-form-' . $form['id'];
				$element['url']        = GFWEBAPI_API_BASE_URL . '/forms/' . $form['id'] . '/entries.json?schema=mtd';
				$section               = array();
				$section['elements'][] = $element;
				$data['sections'][]    = $section;
			}

			return $data;
		}

		public static function mtd_transform_entry_data( $entry ) {
			$data                  = array();
			$root_element['type']  = 'root';
			$root_element['title'] = $entry['id'] . ': ' . $entry['date_created'];
			$root_element['id']    = 'id-entry-' . $entry['id'];

			$form_id = rgar( $entry, 'form_id' );
			$form    = RGFormsModel::get_form_meta( $form_id );
			$fields  = $form['fields'];

			foreach ( $fields as $field ) {
				$field_data           = array();
				$field_data['header'] = $field->label;
				$elements             = array();
				$value                = RGFormsModel::get_lead_field_value( $entry, $field );

				if ( is_array( $value ) && isset( $field->choices ) ) {
					$choices = $field->choices;

					foreach ( $choices as $choice ) {
						$found = false;
						foreach ( $value as $item ) {
							if ( $item == rgar( $choice, 'value' ) ) {
								$found = true;
								break;
							}
						}
						$element = array();

						$element['type']    = 'checkbox';
						$element['caption'] = $choice['text'];
						$element['value']   = $found;
						$elements[]         = $element;
					}
				} else {
					$element            = array();
					$element['type']    = 'string';
					$element['caption'] = GFFormsModel::get_choice_text( $field, $value );

					$elements[] = $element;
				}
				$field_data['elements'] = $elements;
				$data[]                 = $field_data;
			}
			$root_element['sections'] = $data;

			return $root_element;
		}

		/**
		 * Generate a rand hash.
		 *
		 * @since  2.4-beta-1
		 *
		 * @return string
		 */
		public function rand_hash() {
			if ( function_exists( 'openssl_random_pseudo_bytes' ) ) {
				return bin2hex( openssl_random_pseudo_bytes( 20 ) );
			} else {
				return sha1( wp_rand() );
			}
		}

		/**
		 * Hashes specified text.
		 *
		 * @since  2.4-beta-1
		 *
		 * @param  string $data Message to be hashed.
		 * @return string Hashed data
		 */
		public static function api_hash( $data ) {
			return hash_hmac( 'sha256', $data, 'gf-api' );
		}

	}
	new GFWebAPI();
}

Open in new window

Avatar of Terry Woods
Terry Woods
Flag of New Zealand image

The error is originating from the "Gravity Forms" plugin. To help diagnose the error, I recommend moving the code for the plugin to a  temporary folder outside of your web root.

The plugin folder is /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/gravityforms

ie you can move the folder gravityforms from the /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/ folder to somewhere like /home/mivn8z69yz1h/non_public_html/

Once you get the site running, it's a good time to take a backup, in case you need to restore back to that point.

Sometimes the issue with a broken plugin is an incompatability of a particular version with other software, such as with a newer version of WordPress. If you can login to the website dashboard once the plugin has been removed, then you could try re-installing the latest version of Gravity Forms from the Plugins > Add Plugin page. Note that if you've purchased a Premium version of the plugin, then you may have a different installation procedure.

Before re-installing the plugin, you may also want to try updating the WordPress core software to the latest version. I'm reasonably confident that Gravity Forms is a well maintained, reputable and widely used plugin, so you should find that the latest version of it should work fine with the latest version of WordPress.
ASKER CERTIFIED SOLUTION
Avatar of David Favor
David Favor
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
While the error is showing up related to the Gravity Forms plugin, the missing site_url() function suggests WordPress core has been compromised (hacked) or clobbered in some way or there's a very old version of WordPress running.

So the problem appears related to WordPress core, rather than the actual Gravity Forms plugin.
Avatar of Chris Slack
Chris Slack

ASKER

I want to thank all of you. I was able to restore a better copy. FileZilla ftp wasn't cutting it. So I disable one plugin at a time until it worked.
I'm still having an issue with 2 plugins backupbuddy and slider revolution. You can look at the page and you see Slider error.

danatannenbuammd.com

BackupBuddy Error:
Fatal error: Class 'pb_backupbuddy_actionscore' not found in /home/mivn8z69yz1h/public_html/danatannenbaummd.com/wp/wordpress/wp-content/plugins/backupbuddy/controllers/actions.php on line 13

Open in new window


Slider Revolution error msg is:
Revolution Slider Error: The param Slider Width should not be empty.

Open in new window


Any advise would be great I don't know much about plugins.

Thanks
1) BackupBuddy Fix: Install latest version. Open a ticket with iThemes if problem persists.

Note: Since there are no reported problems related to the pb_backupbuddy_actionscore class missing, your site might also be hacked.

First start with installing latest version, which is currently v8.4.19.0 as of this morning.

2) RevSlider Fix: Replace this code as it's a fairly constant source of site hacks + generally has many problems. Likely installing latest version will also fix this problem. Open a ticket with the developer if problem persists.