File "FrmProEntriesController.php"

Full path: /home/bud/public_html/swamp/wp-admin/wp-content/plugins/formidable-pro/classes/controllers/FrmProEntriesController.php
File size: 115.56 KB
MIME-type: text/x-php
Charset: utf-8

<?php

if ( ! defined( 'ABSPATH' ) ) {
	die( 'You are not allowed to call this page directly.' );
}

class FrmProEntriesController {

	public static function remove_fullscreen( $init ) {
		if ( isset( $init['plugins'] ) ) {
            $init['plugins'] = str_replace('wpfullscreen,', '', $init['plugins']);
            $init['plugins'] = str_replace('fullscreen,', '', $init['plugins']);
        }
        return $init;
    }

	public static function data_sort( $options ) {
        natcasesort($options); //TODO: add sorting options
        return $options;
    }

	/* Back End CRUD */
	public static function show_comments( $entry ) {
		$id = $entry->id;
		$user_ID = get_current_user_id();

		if ( $_POST && isset($_POST['frm_comment']) && ! empty($_POST['frm_comment']) ) {
			$meta_key   = '';
			$meta_value = array(
				'comment' => $_POST['frm_comment'],
				'user_id' => $user_ID,
			);
			FrmEntryMeta::add_entry_meta( $_POST['item_id'], 0, $meta_key, $meta_value );
			//send email notifications
		}

		$comments = FrmEntryMeta::getAll( array( 'item_id' => $id, 'field_id' => 0), ' ORDER BY it.created_at ASC', '', true);
		$date_format = get_option( 'date_format' );
		$time_format = get_option( 'time_format' );

		include FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/show.php';
	}

	public static function add_new_entry_link( $form ) {
        FrmProEntriesHelper::show_new_entry_button($form);
    }

	public static function new_entry() {
		$form_id = FrmAppHelper::get_param( 'form', '', 'get', 'absint' );
		if ( $form_id ) {
            $form = FrmForm::getOne($form_id);
            self::get_new_vars('', $form);
        } else {
             include(FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/new-selection.php');
        }
    }

	public static function create() {
        if ( ! current_user_can('frm_create_entries') ) {
            return FrmEntriesController::display_list();
        }

		$params = FrmForm::get_admin_params();
		$record = false;
		$form   = false;

        if ( $params['form'] ) {
            $form = FrmForm::getOne( $params['form'] );
        }

        if ( ! $form ) {
            return;
        }

		$errors = FrmEntryValidate::validate( wp_unslash( $_POST ) );

        if ( count($errors) > 0 ) {
            self::get_new_vars($errors, $form);
            return;
        }

		if ( ( isset( $_POST[ 'frm_page_order_' . $form->id ] ) || FrmProFormsHelper::going_to_prev( $form->id ) ) && ! FrmProFormsHelper::saving_draft() ) {
            self::get_new_vars('', $form);
            return;
        }

		$_SERVER['REQUEST_URI'] = str_replace( '&frm_action=new', '', FrmAppHelper::get_server_value( 'REQUEST_URI' ) );

        global $frm_vars;
        if ( empty( $frm_vars['created_entries'][ $form->id ] ) ) {
			$frm_vars['created_entries'][ $form->id ] = array();
        }

        if ( ! isset( $frm_vars['created_entries'][ $_POST['form_id'] ]['entry_id'] ) ) {
			$record                                               = FrmEntry::create( $_POST );
			$frm_vars['created_entries'][ $form->id ]['entry_id'] = $record;
        }

        if ( $record ) {
            if ( FrmProFormsHelper::saving_draft() ) {
                $message = __( 'Draft was Successfully Created', 'formidable-pro' );
            } else {
                $message = __( 'Entry was Successfully Created', 'formidable-pro' );
            }

            self::get_edit_vars($record, $errors, $message);
        } else {
            self::get_new_vars($errors, $form);
        }
    }

	public static function edit() {
		$id = FrmAppHelper::get_param( 'id', '', 'get', 'absint' );

        if ( ! current_user_can('frm_edit_entries') ) {
            return FrmEntriesController::show($id);
        }

        return self::get_edit_vars($id);
    }

	public static function update() {
		$id = FrmAppHelper::get_param( 'id', '', 'get', 'absint' );

        if ( ! current_user_can('frm_edit_entries') ) {
            return FrmEntriesController::show($id);
        }

        $message = '';
		$errors = FrmEntryValidate::validate( wp_unslash( $_POST ) );

		if ( empty( $errors ) ) {
			if ( isset( $_POST['form_id'] ) && ( isset( $_POST[ 'frm_page_order_' . $_POST['form_id'] ] ) || FrmProFormsHelper::going_to_prev( $_POST['form_id'] ) ) && ! FrmProFormsHelper::saving_draft() ) {
                return self::get_edit_vars($id);
			} else {
                FrmEntry::update( $id, $_POST );
                if ( isset($_POST['form_id']) && FrmProFormsHelper::saving_draft() ) {
                    $message = __( 'Draft was Successfully Updated', 'formidable-pro' );
                } else {
                    $message = __( 'Entry was Successfully Updated', 'formidable-pro' );
                }

				$message .= ' <a href="?page=formidable-entries&form=' . absint( $_POST['form_id'] ) . '"> ' . __( 'Go Back to Entries', 'formidable-pro' ) . '</a>';
            }
        }

        return self::get_edit_vars($id, $errors, $message);
    }

	public static function duplicate() {
		$params = FrmForm::get_admin_params();

        if ( ! current_user_can('frm_create_entries') ) {
            return FrmEntriesController::show($params['id']);
        }

		$message = '';
		$errors  = '';

        $record = FrmEntry::duplicate( $params['id'] );
        if ( $record ) {
            $message = __( 'Entry was Successfully Duplicated', 'formidable-pro' );
        } else {
            $errors = __( 'There was a problem duplicating that entry', 'formidable-pro' );
        }

        if ( ! empty( $errors ) ) {
			return FrmEntriesController::display_list( $message, $errors );
        } else {
			return self::get_edit_vars( $record, array(), $message );
        }
    }

	/**
	 * Delete all entries in a form when the 'delete all' button is clicked.
	 *
	 * @since 4.02.04
	 */
	public static function destroy_all() {
		if ( ! current_user_can( 'frm_delete_entries' ) || ! wp_verify_nonce( FrmAppHelper::simple_get( '_wpnonce', '', 'sanitize_text_field' ), '-1' ) ) {
			$frm_settings = FrmAppHelper::get_settings();
			wp_die( esc_html( $frm_settings->admin_permission ) );
		}

		$params  = FrmForm::get_admin_params();
		$message = '';
		$form_id = (int) $params['form'];

		if ( $form_id ) {
			$entry_ids = FrmDb::get_col( 'frm_items', array( 'form_id' => $form_id ) );
			$action    = FrmFormAction::get_action_for_form( $form_id, 'wppost', 1 );

			if ( $action ) {
				// This action takes a while, so only trigger it if there are posts to delete.
				foreach ( $entry_ids as $entry_id ) {
					do_action( 'frm_before_destroy_entry', $entry_id );
					unset( $entry_id );
				}
			}

			$results = self::delete_form_entries( $form_id );
			if ( $results ) {
				$message = 'destroy_all';
				FrmEntry::clear_cache();
			}
		} else {
			$message = 'no_entries_selected';
		}

		$url = admin_url( 'admin.php?page=formidable-entries&frm-full=1&frm_action=list&form=' . absint( $form_id ) );

		if ( $message ) {
			$url .= '&message=' . $message;
		}

		wp_safe_redirect( $url );
		die();
	}

	/**
	 * @since 4.02.04
	 *
	 * @param int $form_id
	 */
	private static function delete_form_entries( $form_id ) {
		global $wpdb;

		$form_ids = self::get_child_form_ids( $form_id );

		$meta_query  = $wpdb->prepare( "DELETE em.* FROM {$wpdb->prefix}frm_item_metas as em INNER JOIN {$wpdb->prefix}frm_items as e on (em.item_id=e.id) WHERE form_id=%d", $form_id );
		$entry_query = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}frm_items WHERE form_id=%d", $form_id );

		if ( ! empty( $form_ids ) ) {
			$form_query  = ' OR form_id in (' . $form_ids . ')';
			$meta_query  .= $form_query;
			$entry_query .= $form_query;
		}

		$wpdb->query( $meta_query ); // WPCS: unprepared SQL ok.

		return $wpdb->query( $entry_query ); // WPCS: unprepared SQL ok.
	}

	/**
	 * @since 4.02.04
	 *
	 * @param int $form_id
	 * @param bool|string $implode
	 */
	private static function get_child_form_ids( $form_id, $implode = ',' ) {
		$form_ids = FrmProForm::get_child_form_ids( $form_id );
		if ( $implode ) {
			$form_ids = implode( $implode, $form_ids );
		}

		return $form_ids;
	}

	public static function bulk_actions( $action = 'list-form' ) {
		$params = FrmForm::get_admin_params();
        $errors = array();
        $bulkaction = '-1';

		if ( $action == 'list-form' ) {
            if ( $_REQUEST['bulkaction'] != '-1' ) {
                $bulkaction = sanitize_text_field( $_REQUEST['bulkaction'] );
            } else if ( $_POST['bulkaction2'] != '-1' ) {
                $bulkaction = sanitize_text_field( $_REQUEST['bulkaction2'] );
			}
		} else {
            $bulkaction = str_replace('bulk_', '', $action);
        }

		$items = FrmAppHelper::get_param( 'item-action', '', 'get', 'sanitize_text_field' );
		if ( empty( $items ) ) {
            $errors[] = __( 'No entries were specified', 'formidable-pro' );
		} else {
            $frm_settings = FrmAppHelper::get_settings();

            if ( ! is_array($items) ) {
                $items = explode(',', $items);
            }

			if ( $bulkaction == 'delete' ) {
				if ( ! current_user_can( 'frm_delete_entries' ) ) {
                    $errors[] = $frm_settings->admin_permission;
				} else {
                    if ( is_array($items) ) {
                        foreach ( $items as $item_id ) {
                            FrmEntry::destroy($item_id);
                        }
                    }
                }
			} else if ( $bulkaction == 'csv' ) {
                FrmAppHelper::permission_check('frm_view_entries');

                $form_id = $params['form'];
                if ( ! $form_id ) {
					$form = FrmForm::get_published_forms( array(), 1 );
                    if ( ! empty($form) ) {
                        $form_id = $form->id;
                    } else {
                        $errors[] = __( 'No form was found', 'formidable-pro' );
                    }
                }

                if ( $form_id && is_array($items) ) {
					echo '<script type="text/javascript">window.onload=function(){location.href="' . esc_url_raw( admin_url( 'admin-ajax.php?form=' . $form_id . '&action=frm_entries_csv&item_id=' . implode( ',', $items ) ) ) . '";}</script>';
                }
            }
        }
		FrmEntriesController::display_list( '', $errors );
    }

    /* Front End CRUD */

	/*
	 * Determine if this is a new entry or if we're editing an old one
	 */
	public static function maybe_editing( $continue, $form_id, $action = 'new' ) {
		$form_submitted = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
        if ( $action == 'new' || $action == 'preview' ) {
            $continue = true;
        } else {
			$continue = ( $form_submitted && (int) $form_id != $form_submitted );
        }

        return $continue;
    }

	public static function check_draft_status( $values, $id ) {
		if ( ! FrmProEntriesHelper::get_field( 'is_draft', $id ) || $values['is_draft'] ) {
			// if entry draft status is unchanged
			return $values;
		}

        //add the create hooks since the entry is switching draft status
        add_action('frm_after_update_entry', 'FrmProEntriesController::add_published_hooks', 2, 2);

		/**
		 * Do something when a draft entry is officially saved
		 *
		 * @since 3.0.08
		 */
		do_action(
			'frm_after_complete_entry_processed',
			array(
				'entry_id' => $id,
				'form'     => $values['form_id'],
			)
		);

        //change created timestamp
        $values['created_at'] = $values['updated_at'];

        return $values;
    }

	public static function remove_draft_hooks( $entry_id ) {
        if ( ! FrmProEntriesHelper::get_field('is_draft', $entry_id) ) {
            return;
        }

        // don't let sub entries remove these hooks
        $entry = FrmEntry::getOne($entry_id);
        if ( $entry->parent_item_id ) {
            return;
        }

        //remove hooks if saving as draft
        remove_action('frm_after_create_entry', 'FrmProEntriesController::set_cookie', 20);
        remove_action('frm_after_create_entry', 'FrmFormActionsController::trigger_create_actions', 20);
		add_action( 'frm_after_create_entry', 'FrmProFormActionsController::trigger_draft_actions', 10, 2 );

		// trigger after draft save hook
		do_action( 'frm_after_draft_entry_processed', array( 'entry_id' => $entry_id, 'form' => $entry->form_id ) );
    }

    //add the create hooks since the entry is switching draft status
	public static function add_published_hooks( $entry_id, $form_id ) {
		do_action( 'frm_after_create_entry', $entry_id, $form_id );
		do_action( 'frm_after_create_entry_' . $form_id, $entry_id );
		remove_action( 'frm_after_update_entry', 'FrmProEntriesController::add_published_hooks', 2 );
		remove_action( 'frm_after_update_entry', 'FrmProFormActionsController::trigger_update_actions', 10, 2 );
	}

	public static function process_update_entry( $params, $errors, $form, $args ) {
		self::maybe_autosave_on_page_turn( $errors, $form );

		if ( $params['action'] === 'create' && FrmFormsController::just_created_entry( $form->id ) ) {
			self::success_after_create( $params, $form, $args );
		} elseif ( $params['action'] === 'update' && empty( $errors ) ) {
			if ( self::entry_previously_saved( $params ) ) {
				return;
			}

            //check if user is allowed to update
            if ( ! FrmProEntriesHelper::user_can_edit( (int) $params['id'], $form ) ) {
                $frm_settings = FrmAppHelper::get_settings();
                wp_die(do_shortcode($frm_settings->login_msg));
            }

            //update, but don't check for confirmation if saving draft
            if ( FrmProFormsHelper::saving_draft() ) {
                FrmEntry::update( $params['id'], $_POST );
				do_action( 'frm_after_draft_entry_processed', array( 'entry_id' => $params['id'], 'form' => $form ) );
                return;
            }

            //don't update if going back
			if ( isset( $_POST[ 'frm_page_order_' . $form->id ] ) || FrmProFormsHelper::going_to_prev( $form->id ) ) {
                return;
            }

            FrmEntry::update( $params['id'], $_POST );

			$success_args = array( 'action' => $params['action'], 'id' => $params['id'] );
            if ( $params['action'] != 'create' && FrmProEntriesHelper::is_new_entry($params['id']) ) {
                $success_args['action'] = 'create';
            }

			self::trigger_redirect( $form, $success_args, $args );
		} elseif ( $params['action'] === 'destroy' ) {
            //if the user who created the entry is deleting it
            self::ajax_destroy($form->id, false, false);
        }
    }

	private static function success_after_create( $params, $form, $args ) {
		global $frm_vars;
		$entry_id     = $frm_vars['created_entries'][ $form->id ]['entry_id'];
		$params['id'] = $entry_id;
		self::set_cookie( $entry_id, $form->id );
	}

	private static function trigger_redirect( $form, $params, $args ) {
		$is_autosave = FrmAppHelper::get_post_param( 'frm_autosaving', '', 'sanitize_text_field' );
		if ( $is_autosave == 1 ) {
			return;
		}

		$conf_method = self::get_conf_method_after_save( $form, $params );
		if ( $conf_method == 'redirect' ) {
			FrmFormsController::trigger_redirect( $form, $params, $args );
		}
	}

	private static function &entry_previously_saved( $params ) {
		global $frm_vars;
		$saved = ( isset( $frm_vars['saved_entries'] ) && in_array( (int) $params['id'], (array) $frm_vars['saved_entries'] ) );
		return $saved;
	}

	/**
	 * @since 2.3
	 */
	private static function maybe_autosave_on_page_turn( $errors, $form ) {
		if ( ! empty( $errors ) || ! is_user_logged_in() ) {
			return;
		}

		// the entry is already getting saved
		$last_page = ! isset( $_POST[ 'frm_page_order_' . $form->id ] );
		if ( $last_page || FrmProFormsHelper::saving_draft() ) {
			return;
		}

		$drafts_allowed = FrmForm::get_option( array( 'form' => $form, 'option' => 'save_draft' ) );
		if ( $drafts_allowed ) {
			self::autosave_on_page_turn( $form );
		}
	}

	/**
	 * @since 2.3
	 */
	private static function autosave_on_page_turn( $form ) {
		$params = $_POST;
		$params['frm_saving_draft'] = true;
		$params['is_draft'] = 1;

		if ( ! isset( $params['action'] ) ) {
			$params['action'] = $params['frm_action'];
		}

		if ( $params['action'] == 'create' || $params['action'] == 'frm_entries_create' ) {
			global $frm_vars;
			$_POST['frm_autosaving'] = 1;
			if ( empty( $frm_vars['created_entries'][ $form->id ] ) ) {
				$frm_vars['created_entries'][ $form->id ] = array( 'errors' => array() );
			}
			$frm_vars['created_entries'][ $form->id ]['entry_id'] = FrmEntry::create( $params );

		} else if ( $params['action'] == 'update' || $params['action'] == 'frm_entries_update' ) {
			if ( ! FrmProEntriesHelper::user_can_edit( absint( $params['id'] ), $form ) ) {
				return;
			}

			$entry = FrmEntry::getOne( $params['id'] );
			if ( $entry->is_draft ) {
				$_POST['frm_autosaving'] = 1;
				FrmEntry::update( $entry->id, $params );
			}
		}
	}

	public static function edit_update_form( $params, $fields, $form, $title, $description ) {
        global $frm_vars;

		FrmProFormState::set_initial_value( 'title', $title );
		FrmProFormState::set_initial_value( 'description', $description );

		self::load_wp_editor_assets( $fields, $form );

        $continue = true;
		$args     = array(
			'form'             => $form,
			'fields'           => $fields,
			'show_title'       => $title,
			'show_description' => $description,
			'params'           => $params,
		);

		if ( 'edit' === $params['action'] ) {
			// For initial form load when editing
			self::maybe_show_front_end_editable_entry_on_first_load( $args, $continue );
		} elseif ( 'update' === $params['action'] && $params['posted_form_id'] == $form->id ) {
			// For next/submit/previous/save draft clicks
			self::show_front_end_editable_entry_after_submit_click( $args, $continue );
        } elseif ( 'destroy' === $params['action'] ) {
            self::front_destroy_entry($form);
		} elseif ( isset( $frm_vars['editing_entry'] ) && $frm_vars['editing_entry'] ) {
			// For entry_id=x, initial load only
			self::maybe_show_front_end_editable_entry_with_entry_id_param( $args, $continue);
        } else {
            self::allow_front_create_entry($form, $continue);
        }

		self::check_form_status_options( $form, $continue );

		self::remove_opposite_continue_to_new_filter( $continue );
    }

	/**
	 * Loads necessary WP Editor assets for Rich Text fields with
	 * AJAX-enabled forms.
	 *
	 * @since 4.06.02
	 *
	 * @param array   $fields Array of fields and its properties.
	 * @param object  $form   Object representing the current Form.
	 */
	private static function load_wp_editor_assets( $fields, $form ) {
		// This is only needed when AJAX submission is enabled for the form.
		if ( ! FrmProForm::is_ajax_on( $form ) || FrmAppHelper::is_admin() ) {
			return;
		}

		foreach ( $fields as $field ) {

			// Check for an `rte` (Rich-text) field.
			$field_type = FrmField::get_option( $field, 'original_type' );
			if ( 'rte' === $field_type ) {
				$field_obj = FrmFieldFactory::get_field_type( 'rte' );
				$field_obj->load_default_rte_script();
				break;
			}
		}
	}

	/**
	 * @since 3.04
	 *
	 * @param object $form
	 */
	private static function check_form_status_options( $form, &$continue ) {
		if ( $continue && ! FrmProForm::is_open( $form ) ) {
			$continue = false;
			if ( isset( $form->options['closed_msg'] ) ) {
				$message = $form->options['closed_msg'];
			} else {
				$default_opts = FrmProFormsHelper::get_default_opts();
				$message      = $default_opts['closed_msg'];
			}
			$message = do_shortcode( $message );
			echo wp_kses_post( $message );
		}
	}

	private static function remove_opposite_continue_to_new_filter( $continue ) {
		if ( $continue === true ) {
			remove_filter('frm_continue_to_new', '__return_false', 15);
			add_filter('frm_continue_to_new', '__return_true', 15);
		} else {
			remove_filter('frm_continue_to_new', '__return_true', 15);
			add_filter('frm_continue_to_new', '__return_false', 15);
		}
	}

	/**
	 * Load form and entry for editing if user has permission and entry exists
	 * Used on initial load only, not on page turns
	 *
	 * @since 2.01.0
	 *
	 * @param array $args (always contains 'form', 'fields' , 'show_title', and 'show_description')
	 * @param boolean $continue
	 */
	private static function maybe_show_front_end_editable_entry_on_first_load( $args, &$continue ) {
		global $wpdb, $frm_vars;

		$entry_id  = ( isset( $frm_vars['editing_entry'] ) && $frm_vars['editing_entry'] ) ? $frm_vars['editing_entry'] : '';
		$entry_key = FrmAppHelper::get_param( 'entry', $entry_id, 'get', 'sanitize_title' );

        $query = array( 'it.form_id' => $args['form']->id );

        if ( $entry_key ) {
            $query[1] = array( 'or' => 1, 'it.id' => $entry_key, 'it.item_key' => $entry_key );
			$in_form = FrmDb::get_var( $wpdb->prefix . 'frm_items it', $query );

            if ( ! $in_form ) {
                $entry_key = false;
                unset( $query[1] );
            }
            unset($in_form);
        }

        $entry = FrmProEntriesHelper::user_can_edit( $entry_key, $args['form'] );
        if ( ! $entry ) {
            return;
        }

		if ( ! is_array( $entry ) ) {
			$entry = FrmEntry::getAll( $query, '', 1, true );
		}

		if ( ! empty( $entry ) ) {
			global $frm_vars;
			$entry = reset($entry);
			$frm_vars['editing_entry'] = $entry->id;

			self::show_entry_on_first_load_for_editing( $entry, $args );
			$continue = false;
        }
    }

	/**
	* Load the form for editing when entry_id=x shortcode is used
	*
	* @param array $args (contains form, fields, show_title, and show_description)
	* @param boolean $continue
	*/
	private static function maybe_show_front_end_editable_entry_with_entry_id_param( $args, &$continue ) {
		global $frm_vars;

		$entry_id = false;
		if ( is_numeric( $frm_vars['editing_entry'] ) ) {
			// For entry_id=x in shortcode
			$entry_id = $frm_vars['editing_entry'];
		} elseif ( $frm_vars['editing_entry'] == 'last' ) {
			// For entry_id="last" in shortcode

			// Get the last entry submitted by the current user
			$user_ID = get_current_user_id();
			$where = array(
				'user_id' => $user_ID,
				'form_id' => $args['form']->id,
			);
			$entry_id = FrmDb::get_col( 'frm_items', $where, 'id', array(), ' LIMIT 1' );
        }

		if ( ! $entry_id ) {
			return;
		}

		if ( ! FrmProEntriesHelper::user_can_edit( $entry_id, $args['form'] ) ) {
			return;
		}

        $frm_vars['editing_entry'] = $entry_id;
		$entry = FrmEntry::getOne( $entry_id, true );

		self::show_entry_on_first_load_for_editing( $entry, $args );

        $continue = false;
    }

    private static function front_destroy_entry( $form ) {
        //if the user who created the entry is deleting it
        self::ajax_destroy($form->id, false);
    }

	/**
	 * Show the form/entry after clicking Next, Previous, Update, Submit, or Save Draft
	 *
	 * @since 2.01.0
	 *
	 * @param array $args (always contains 'form', 'fields' , 'show_title', 'show_description', and 'params')
	 * @param boolean $continue
	 */
	private static function show_front_end_editable_entry_after_submit_click( $args, &$continue ) {
        global $frm_vars;

		// Initialize basic entry info
		$entry_id = $args['params']['id'];
		$entry = FrmEntry::getOne( $entry_id, true );
		$frm_vars['editing_entry'] = $entry_id;

		// Add to args
		$args['errors'] = self::get_posted_form_errors( $frm_vars, $args['form'] );
		$field_args = array(
			'parent_form_id' => $args['form']->id,
			'fields' => $args['fields'],
			'save_draft_click' => FrmProFormsHelper::saving_draft(),
		);
		$args['values'] = self::setup_entry_values_for_editing( $entry, $field_args );
		self::add_submit_value_to_values( $args['form'], $args['values'] );
		$args['submit_text'] = self::get_submit_button_text_for_editing_entry( $entry, $args['values'], $args['form'] );

		if ( self::update_button_was_clicked( $args ) ) {
			// If Update/Submit was clicked
			if ( FrmProEntriesHelper::user_can_edit( $entry_id, $args['form'] ) ) {
				self::do_on_update_settings( $entry, $args );
			} else {
				// entry is no longer editable after draft is saved
				self::do_on_create_settings( $entry, $args );
			}
		} else {
			// If Save Draft, Next, or Previous was clicked
			$args['show_form'] = true;
			$args['jump_to_form'] = true;
			$args['conf_message'] = self::maybe_get_save_draft_message( $args['form'], $entry_id );
			self::show_front_end_form_with_entry( $entry, $args );
		}

		$continue = false;
    }

	/**
	 * Adds submit value in $form object to $values array.
	 *
	 * @since 4.06.02
	 *
	 * @param object $form   Form object.
	 * @param array  $values Array of values, used to set submit button text, among other things.
	 */
	private static function add_submit_value_to_values( $form, &$values ) {
		if ( isset( $form->submit_value ) ) {
			$values['submit_value'] = $form->submit_value;
			return;
		}

		if ( isset( $form->options['submit_value'] ) ) {
			$values['submit_value'] = $form->options['submit_value'];
		}
	}

	/**
	 * Show the message + form after the first Save Draft click (on front-end only)
	 * Replaces FrmProEntriesController::show_responses
	 *
	 * @since 2.01.0
	 *
	 * @param int $entry_id
	 * @param array $args
	 */
	public static function show_form_after_first_save_draft_click( $entry_id, $args ) {
		global $frm_vars;
		$frm_vars['editing_entry'] = $entry_id;

		$entry = FrmEntry::getOne( $entry_id );
		$field_args = array(
			'parent_form_id' => $args['form']->id,
			'fields' => $args['fields'],
			'save_draft_click' => true,
		);
		$args['values'] = self::setup_entry_values_for_editing( $entry, $field_args );
		$args['submit_text'] = self::get_submit_button_text_for_editing_entry( $entry, $args['values'], $args['form'] );
		$args['show_form'] = true;
		$args['jump_to_form'] = true;
		$args['errors'] = array();

		self::show_front_end_form_with_entry( $entry, $args );
	}

	/**
	 * Display a success message and possibly the form after single editable entry is submitted
	 * Replaces FrmProEntriesController::show_responses
	 *
	 * @since 2.01.0
	 * @param int $entry_id
	 * @param array $args (always contains 'form', 'fields', 'show_title', and 'show_description')
	 */
	public static function show_form_after_single_editable_entry_submission( $entry_id, $args ) {
		self::show_form_after_first_save_draft_click( $entry_id, $args );
	}

	/**
	 * Get errors when validating server-side
	 *
	 * @since 2.01.0
	 *
	 * @param array $frm_vars
	 * @param object $form
	 * @return array
	 */
	private static function get_posted_form_errors( $frm_vars, $form ) {
		if ( isset( $frm_vars['created_entries'][ $form->id ] ) ) {
			$errors = $frm_vars['created_entries'][ $form->id ]['errors'];
		} else {
			$errors = false;
		}
		return $errors;
	}

	/**
	 * If a draft is being saved, get the save draft message
	 *
	 * @since 2.01.0
	 *
	 * @param object $form
	 * @param int $entry_id
	 * @return string $message
	 */
	private static function maybe_get_save_draft_message( $form, $entry_id ) {
		$message = '';
		if ( FrmProFormsHelper::saving_draft() ) {
			$success_args = array( 'action' => self::get_current_entry_action( $entry_id ) );
			$message = self::confirmation( 'message', $form, $form->options, $entry_id, $success_args );
		}

		return $message;
	}

	/**
	 * Check to see if user is allowed to create another entry
	 */
	private static function allow_front_create_entry( $form, &$continue ) {
		$errors = array();
		if ( FrmProFormsHelper::visitor_already_submitted( $form, $errors ) ) {
			echo do_shortcode( reset( $errors ) );
			$continue = false;
		}
	}

	/**
	 * This function should only be used when editing an entry (on front-end only)
	 * Replaces FrmProEntriesController::show_responses
	 *
	 * @since 2.01.0
	 * @param object $entry
	 * @param array $args (always contains 'form', 'fields', 'show_title', and 'show_description')
	 */
	private static function show_entry_on_first_load_for_editing( $entry, $args ) {
		$field_args = array(
			'parent_form_id' => $args['form']->id,
			'fields' => $args['fields'],
		);
		$args['values'] = self::setup_entry_values_for_editing( $entry, $field_args );
		$args['submit_text'] = self::get_submit_button_text_for_editing_entry( $entry, $args['values'], $args['form'] );
		$args['errors'] = array();
		$args['show_form'] = true;

		self::show_front_end_form_with_entry( $entry, $args );
	}

	/**
	 * Update the global $frm_vars so CSS and JavaScript gets loaded correctly
	 *
	 * @since 2.01.0
	 *
	 * @param array $args always contains 'form', 'fields', 'show_title', 'show_description', 'values', 'errors',
	 *     'submit_text', and 'show_form'
	 */
	private static function update_global_vars_for_entry_editing( &$args ) {

		if ( isset( $args['form']->options['show_form'] ) && $args['form']->options['show_form'] ) {
			//Do nothing because JavaScript is already loaded
			// Make sure Formidable CSS is loaded
			global $frm_vars;
			if ( $args['values']['custom_style'] ) {
				$frm_vars['load_css'] = true;
			}
		} else {
			self::load_form_scripts(
				array(
					'style' => $args['values']['custom_style'],
				)
			);
		}
	}

	/**
	 * Set up all the necessary data for editing an entry
	 * This is now used in place of FrmAppHelper::setup_edit_vars when editing entries
	 *
	 * @since 2.01.0
	 *
	 * @param object $entry
	 * @param array $args (always contains 'parent_form_id' and 'fields'; if repeating, will contain 'parent_field_id',
	 *     'key_pointer' and 'repeating'; if embedded, will contain in_embed_form)
	 * @return array $values
	 */
	public static function setup_entry_values_for_editing( $entry, $args ) {
		$values = array(
			'id' => $entry->id,
			'fields' => array(),
		);

		foreach ( array( 'name', 'description' ) as $var ) {
			$default_val = isset( $entry->{$var} ) ? $entry->{$var} : '';
			$values[ $var ] = FrmAppHelper::get_param( $var, $default_val, 'get', 'wp_kses_post' );
			FrmAppHelper::sanitize_value( 'wp_specialchars_decode', $values[ $var ] );

			unset($var, $default_val);
		}

		$values['description'] = FrmAppHelper::use_wpautop( $values['description'] );

		$fields = $args['fields'];
		unset( $args['fields'] );
		$values['fields'] = FrmProFieldsController::setup_field_data_for_editing_entry( $entry, $fields, $args );

		FrmProFormsController::setup_form_data_for_editing_entry( $entry, $values );

		$values = FrmEntriesHelper::setup_edit_vars( $values, $entry );

		return $values;
	}

	/**
	 * Get the text on the Submit button when editing an entry
	 * Remember the Submit button may be the Next, Update, or Submit button
	 *
	 * @since 2.01.0
	 *
	 * @param object $entry
	 * @param array $values
	 * @param object $form
	 * @return string $submit_text
	 */
	private static function get_submit_button_text_for_editing_entry( $entry, $values, $form ) {
		global $frm_vars;

		if ( isset( $frm_vars['next_page'][ $form->id ] ) ) {
			// If there is a "Next" page, get the Next button text
			$submit_text = $frm_vars['next_page'][ $form->id ];
			$submit_text = $submit_text->name;
		} else {
			if ( $entry->is_draft ) {
				// If entry is a draft, get the create button text
				if ( isset( $values['submit_value'] ) ) {
					$submit_text = $values['submit_value'];
				} else {
					$frmpro_settings = FrmProAppHelper::get_settings();
					$submit_text = $frmpro_settings->submit_value;
				}
			} else {
				// If entry is not a draft, get the edit button text
				if ( isset( $values['edit_value'] ) ) {
					$submit_text = $values['edit_value'];
				} else {
					$frmpro_settings = FrmProAppHelper::get_settings();
					$submit_text = $frmpro_settings->update_value;
				}
			}
		}

		return $submit_text;
	}

	/**
	 * Determine whether the "Update" button was clicked
	 *
	 * @since 2.01.0
	 *
	 * @param array $args (always contains 'form', 'fields' , 'show_title', 'show_description', 'params', 'values',
	 *     'errors', and 'submit_text')
	 * @return boolean $update_button_was_clicked
	 */
	private static function update_button_was_clicked( &$args ) {
		global $frm_vars;
		$update_button_was_clicked = false;

		$form = $args['form'];

		if ( ! isset( $_POST['item_meta'] ) || $args['errors'] ) {
			// There is no item meta or there are errors, so don't update entry

		} else if ( isset( $frm_vars['prev_page'][ $form->id ] ) || FrmProFormsHelper::going_to_prev( $form->id ) ) {
			// Back or Next was clicked

		} else if ( $form->id != FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' ) ) {
			// This form is NOT the one being submitted/updated

		} else if ( FrmProFormsHelper::saving_draft() ) {
			// Save Draft was clicked

		} else {
			$update_button_was_clicked = true;
		}

		return $update_button_was_clicked;
	}

	/**
	 * Determine whether the form is displayed after edit
	 *
	 * @since 2.01.0
	 *
	 * @param object $form
	 * @return boolean $show_form
	 */
	private static function is_form_displayed_after_edit( $form ) {
		$show_form = ( isset( $form->options['show_form'] ) ) ? $form->options['show_form'] : true;
		$show_form = apply_filters( 'frm_show_form_after_edit', $show_form, $form );
		return $show_form;
	}

	/**
	 * Determine whether the current entry is being created or updated
	 *
	 * @since 2.01.0
	 *
	 * @param int $entry_id
	 * @return boolean
	 */
	private static function get_current_entry_action( $entry_id ) {
		return FrmProEntriesHelper::is_new_entry( $entry_id ) ? 'create' : 'update';
	}

	/**
	 * Get the confirmation method selected for "On Update"
	 *
	 * @since 2.01.0
	 *
	 * @param object $form
	 * @param array $success_args (always includes 'action' )
	 * @return string
	 */
	private static function get_conf_method_after_save( $form, $success_args ) {
		return apply_filters( 'frm_success_filter', 'message', $form, $success_args['action'] );
	}

	/**
	 * Do the "On Update" settings (redirect to URL, show a message, or show content from another page)
	 *
	 * @since 2.01.0
	 *
	 * @param object $entry
	 * @param array $args
	 * $args always contains 'form', 'fields' , 'show_title', 'show_description', 'params', 'values', 'errors', and
	 *     'submit_text'
	 */
	private static function do_on_update_settings( $entry, $args ) {
		$success_args = array( 'action' => self::get_current_entry_action( $entry->id ) );
		$conf_method = self::get_conf_method_after_save( $args['form'], $success_args );

		if ( $conf_method == 'message' ) {
			$args['conf_message'] = self::confirmation( 'message', $args['form'], $args['form']->options, $entry->id, $success_args );
			$args['show_form'] = self::is_form_displayed_after_edit( $args['form'] );
			self::show_front_end_form_with_entry( $entry, $args );
		} else {
			do_action('frm_success_action', $conf_method, $args['form'], $args['form']->options, $entry->id, $success_args );
		}
	}

	/**
	 * Show the editable form/entry on the front-end
	 *
	 * @since 2.01.0
	 *
	 * @param object $entry
	 * @param array $args
	 * $args always contains 'form', 'fields', 'show_title', 'show_description', 'values', 'errors', 'submit_text', and
	 *     'show_form'
	 */
	private static function show_front_end_form_with_entry( $entry, $args ) {
		self::update_global_vars_for_entry_editing( $args );

		// Setup variables for view (maybe do away with this and create a new view)
		$values = $args['values'];
		$user_ID = get_current_user_id();
		$frm_settings = FrmAppHelper::get_settings();
		$title = $args['show_title'];
		$description = $args['show_description'];
		$id = $entry->id;
		$errors = $args['errors'];
		$form = $args['form'];
		$submit = $args['submit_text'];
		$show_form = $args['show_form'];
		$jump_to_form = isset( $args['jump_to_form'] ) ? $args['jump_to_form'] : false;

		$message = isset( $args['conf_message'] ) ? $args['conf_message'] : false;
		if ( $message ) {
			$message = apply_filters( 'frm_main_feedback', $message, $form, $id );
		}

		if ( is_callable( 'FrmFormsController::maybe_load_css' ) ) {
			global $frm_vars;
			FrmFormsController::maybe_load_css( $form, $values['custom_style'], $frm_vars['load_css'] );
		}

		require( FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/edit-front.php');
		add_filter('frm_continue_to_new', 'FrmProEntriesController::maybe_editing', 10, 3);
	}

	private static function do_on_create_settings( $entry, $args ) {
		$conf_method = apply_filters( 'frm_success_filter', 'message', $args['form'], 'create' );

		$args['entry_id'] = $entry->id;
		$args['title'] = $args['show_title'];
		$args['description'] = $args['show_description'];

		$args['conf_method'] = $conf_method;
		FrmFormsController::run_success_action( $args );
	}

    public static function ajax_submit_button() {
        global $frm_vars;

        if ( isset($frm_vars['novalidate']) && $frm_vars['novalidate'] ) {
            echo ' formnovalidate="formnovalidate"';
        }
    }

	public static function get_confirmation_method( $method, $form, $action = 'create' ) {
        $opt = ( $action == 'update' ) ? 'edit_action' : 'success_action';
        $method = ( isset( $form->options[ $opt ] ) && ! empty( $form->options[ $opt ] ) ) ? $form->options[ $opt ] : $method;
        if ( $method != 'message' && FrmProFormsHelper::saving_draft() ) {
            $method = 'message';
        }
        return $method;
    }

    public static function confirmation( $method, $form, $form_options, $entry_id, $args = array() ) {
        $opt = ( ! isset( $args['action'] ) || $args['action'] == 'create' ) ? 'success' : 'edit';

		if ( ( $method == 'page' && is_numeric( $form_options[ $opt . '_page_id' ] ) ) || $method == 'redirect' ) {
			$pass_args = $args;
			$pass_args['conf_method'] = $method;
			$pass_args['form']        = $form;
			$pass_args['entry_id']    = $entry_id;
			FrmFormsController::run_success_action( $pass_args );
		} else {
            $frm_settings = FrmAppHelper::get_settings();
            $frmpro_settings = FrmProAppHelper::get_settings();

            $msg = ( $opt == 'edit' ) ? $frmpro_settings->edit_msg : $frm_settings->success_msg;
			$message = isset( $form->options[ $opt . '_msg' ] ) ? $form->options[ $opt . '_msg' ] : $msg;

            // Replace $message with save draft message if we are saving a draft
            FrmProFormsHelper::save_draft_msg( $message, $form );

			$class = 'frm_message';
			return FrmFormsHelper::get_success_message( compact( 'message', 'form', 'entry_id', 'class' ) );
        }
    }

	public static function delete_entry( $post_id ) {
		// Check that installation has occurred
		$db_version = get_option('frm_db_version');
		if ( ! $db_version ) {
			return;
		}

		$entry = FrmDb::get_row( 'frm_items', array( 'post_id' => $post_id ), 'id' );
		self::maybe_delete_entry( $entry );
    }

	public static function trashed_post( $post_id ) {
        $form_id = get_post_meta( $post_id, 'frm_form_id', true );
		if ( ! $form_id ) {
			return;
		}

		$display = FrmProDisplay::get_auto_custom_display( array( 'form_id' => $form_id ) );
		if ( $display ) {
            update_post_meta( $post_id, 'frm_display_id', $display->ID );
		} else {
            delete_post_meta( $post_id, 'frm_display_id' );
		}
    }

	/**
	 * Allow extra parameters in the frm-show-entry shortcode
	 *
	 * @since 3.01.01
	 */
	public static function show_entry_defaults( $atts ) {
		$atts['date_format']   = '';
		$atts['show_image']    = false;
		$atts['size']          = 'full';
		$atts['image_option_size']  = 'thumbnail';
		$atts['show_image_options'] = true;
		$atts['show_filename'] = false;
		$atts['add_link']      = false;
		$atts['summary']       = false; // whether we're trying to display the summary field
		return $atts;
	}

    public static function create_entry_from_post_box( $post_type, $post = false ) {
        if ( ! $post || ! isset($post->ID) || $post_type == 'attachment' || $post_type == 'link' ) {
            return;
        }

        global $wpdb, $frm_vars;

        //don't show the meta box if there is already an entry for this post
		$post_entry = FrmDb::get_var( $wpdb->prefix . 'frm_items', array( 'post_id' => $post->ID ) );
        if ( $post_entry ) {
            return;
        }

        //don't show meta box if no forms are set up to create this post type
		$actions = FrmFormAction::get_action_for_form( 0, 'wppost' );
        if ( ! $actions ) {
            return;
        }

        $form_ids = array();
        foreach ( $actions as $action ) {
            if ( $action->post_content['post_type'] == $post_type && $action->menu_order ) {
                $form_ids[] = $action->menu_order;
            }
        }

        if ( empty($form_ids) ) {
            return;
        }

		$forms = FrmDb::get_results( 'frm_forms', array( 'id' => $form_ids ), 'id, name' );

        $frm_vars['post_forms'] = $forms;

        if ( current_user_can('frm_create_entries') ) {
            add_meta_box( 'frm_create_entry', __( 'Create Entry in Form', 'formidable-pro' ), 'FrmProEntriesController::render_meta_box_content', null, 'side' );
        }
    }

	public static function render_meta_box_content( $post ) {
        global $frm_vars;
        $i = 1;

        echo '<p>';
        foreach ( (array) $frm_vars['post_forms'] as $form ) {
            if ( $i != 1 ) {
                echo ' | ';
            }

            $i++;
			echo '<a href="javascript:frmCreatePostEntry(' . (int) $form->id . ',' . (int) $post->ID . ')">' . esc_html( FrmAppHelper::truncate( $form->name, 15 ) ) . '</a>';
            unset($form);
        }

        echo '</p>';
    }

    public static function create_post_entry( $id = false, $post_id = false ) {
        if ( FrmAppHelper::doing_ajax() ) {
            check_ajax_referer( 'frm_ajax', 'nonce' );
        }

        if ( ! $id ) {
			$id = absint( $_POST['id'] );
        }

        if ( ! $post_id ) {
			$post_id = absint( $_POST['post_id'] );
        }

        if ( ! is_numeric($id) || ! is_numeric($post_id) ) {
            return;
        }

        $post = get_post($post_id);

        global $wpdb;
        $values = array(
            'description' => __( 'Copied from Post', 'formidable-pro' ),
            'form_id'     => $id,
            'created_at'  => $post->post_date_gmt,
            'name'        => $post->post_title,
			'item_key'    => FrmAppHelper::get_unique_key( $post->post_name, $wpdb->prefix . 'frm_items', 'item_key' ),
            'user_id'     => $post->post_author,
            'post_id'     => $post->ID,
        );

		$results = $wpdb->insert( $wpdb->prefix . 'frm_items', $values );
        unset( $values );

        if ( ! $results ) {
            wp_die();
        }

        $entry_id      = $wpdb->insert_id;
        $user_id_field = FrmField::get_all_types_in_form($id, 'user_id', 1);

        if ( $user_id_field ) {
            $new_values = array(
                'meta_value' => $post->post_author,
                'item_id'    => $entry_id,
                'field_id'   => $user_id_field->id,
                'created_at' => current_time( 'mysql', 1 ),
            );

			$wpdb->insert( $wpdb->prefix . 'frm_item_metas', $new_values );
        }

        $display = FrmProDisplay::get_auto_custom_display( array( 'form_id' => $id, 'entry_id' => $entry_id ) );
        if ( $display ) {
            update_post_meta( $post->ID, 'frm_display_id', $display->ID );
        }

        wp_die();
    }

	public static function get_new_vars( $errors = array(), $form = false, $message = '' ) {
        $description = true;
        $title = false;
        $form = apply_filters('frm_pre_display_form', $form);
        if ( ! $form ) {
			wp_die( esc_html__( 'You are trying to access an entry that does not exist.', 'formidable-pro' ) );
            return;
        }

        $fields = FrmFieldsHelper::get_form_fields( $form->id, $errors );
        $values = $fields ? FrmEntriesHelper::setup_new_vars($fields, $form) : array();

		$submit = self::submit_label( compact( 'form', 'values' ) );

		require( FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/new.php' );
	}

	/**
	 * @since 4.0
	 */
	public static function save_new_entry_button( $atts ) {
		echo FrmProFormsHelper::get_draft_button( $atts['form'], 'button-secondary' );
		$submit = self::submit_label( $atts );
		submit_button( $submit, 'primary', '', false );
	}

	/**
	 * @since 4.0
	 */
	private static function submit_label( $atts ) {
		global $frm_vars;

		$form         = $atts['form'];
		$values       = $atts['values'];
		$frm_settings = FrmAppHelper::get_settings();

		if ( FrmProFormsHelper::is_final_page( $form->id ) ) {
			$submit = ( isset( $values['submit_value'] ) ? $values['submit_value'] : $frm_settings->submit_value );
			if ( isset( $atts['entry'] ) ) {
				if ( isset( $values['edit_value'] ) ) {
					$edit_label = $values['edit_value'];
				} else {
					$frmpro_settings = FrmProAppHelper::get_settings();
					$edit_label      = $frmpro_settings->update_value;
				}

				$submit = $atts['entry']->is_draft ? $submit : $edit_label;
			}
		} else {
			$submit = $frm_vars['next_page'][ $form->id ];
		}

		if ( is_object( $submit ) ) {
            $submit = $submit->name;
		}

		return $submit;
	}

	/**
	 * @since 4.0
	 */
	public static function edit_entry_button( $atts ) {
		if ( $atts['entry']->is_draft ) {
			echo FrmProFormsHelper::get_draft_button( $atts['form'], 'button-secondary' );
		}

		$submit = self::submit_label( $atts );
		echo '<button type="submit" class="button button-primary frm-button-secondary">' . esc_html( $submit ) . '</button>';

		if ( ! FrmProFormsHelper::is_final_page( $atts['form']->id ) ) {
			echo '<button type="submit" class="frm-button-secondary frm_page_skip hide-no-js" data-page="">' . esc_html__( 'Save', 'formidable-pro' ) . '</button>';
		}
	}

	private static function get_edit_vars( $id, $errors = array(), $message = '' ) {
		$description = true;
		$title = false;

		$entry = FrmEntry::getOne( $id, true );
		if ( ! $entry ) {
			wp_die( esc_html__( 'You are trying to access an entry that does not exist.', 'formidable-pro' ) );
			return;
		}

		global $frm_vars;
		$frm_vars['editing_entry'] = $id;

		$form = FrmForm::getOne( $entry->form_id );
		$form = apply_filters( 'frm_pre_display_form', $form );

		$fields = FrmFieldsHelper::get_form_fields( $form->id, $errors );
		$values = FrmAppHelper::setup_edit_vars( $entry, 'entries', $fields );

		/**
		 * Allows modifying the list of fields in the form.
		 *
		 * @since 5.0
		 *
		 * @param array $fields Array of fields.
		 * @param array $args   The arguments. Contains `$args`.
		 */
		$values['fields'] = apply_filters( 'frm_fields_in_form_edit', $values['fields'], compact( 'form' ) );

		$submit = self::submit_label( compact( 'form', 'values', 'entry' ) );

		FrmFormsController::maybe_load_css( $form, $values['custom_style'], $frm_vars['load_css'] );

		require( FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/edit.php' );
	}

	public static function filter_shortcode_value( $value, $tag, $atts, $field ) {
		if ( isset( $atts['striphtml'] ) && $atts['striphtml'] ) {
			self::kses_deep( $atts, $value );
		} elseif ( ! isset( $atts['keepjs'] ) || ! $atts['keepjs'] ) {
			FrmAppHelper::sanitize_value( 'wp_kses_post', $value );
		}

		return self::get_option_label_for_saved_value( $value, $field, $atts );
	}

	/**
	 * @since 2.05.03
	 */
	private static function kses_deep( $atts, &$value ) {
		$allowed_tags = apply_filters( 'frm_striphtml_allowed_tags', array(), $atts );
		if ( is_array( $value ) ) {
			foreach ( $value as $k => $v ) {
				$value[ $k ] = wp_kses( $v, $allowed_tags );
				unset( $k, $v );
			}
		} else {
			$value = wp_kses( $value, $allowed_tags );
		}
	}

	/**
	 * Get the option label from a saved value, if a field has separate values and saved_value="1" is not set
	 *
	 * @since 2.02.14
	 *
	 * @param mixed $value
	 * @param object $field
	 * @param array $atts
	 *
	 * @return array|mixed
	 */
	public static function get_option_label_for_saved_value( $value, $field, $atts = array() ) {
		$show_value  = ( isset( $atts['show'] ) && $atts['show'] == 'value' );
		$saved_value = ( isset( $atts['saved_value'] ) && $atts['saved_value'] );
		if ( $saved_value || $value === false || $show_value ) {
			return $value;
		}

		if ( FrmProImages::showing_images( $field, $atts ) ) {
			return FrmProImages::display( $field, $value, $atts );
		}

		$has_separate_option = in_array( $field->type, array( 'radio', 'checkbox', 'select', 'product' ) ) && FrmField::is_option_true( $field, 'separate_value' );
		if ( ! $has_separate_option ) {
			return $value;
		}

		$f_values = array();
		$f_labels = array();

		$show = ( isset( $atts['show'] ) && $atts['show'] === 'price' ) ? 'price' : 'label';

		foreach ( $field->options as $opt_key => $opt ) {
			if ( ! is_array( $opt ) ) {
				continue;
			}

			$f_labels[ $opt_key ] = isset( $opt[ $show ] ) ? $opt[ $show ] : reset( $opt );
			$f_values[ $opt_key ] = isset( $opt['value'] ) ? $opt['value'] : $f_labels[ $opt_key ];
			if ( $f_labels[ $opt_key ] == $f_values[ $opt_key ] ) {
				unset( $f_values[ $opt_key ], $f_labels[ $opt_key ] );
			}
			unset( $opt_key, $opt );
		}

		if ( ! empty( $f_values ) ) {
			if ( is_array( $value ) ) {
				$value = FrmAppHelper::array_flatten( $value, 'reset' );
			}

			foreach ( (array) $value as $v_key => $val ) {
				if ( in_array( $val, $f_values ) ) {
					$opt = array_search( $val, $f_values );
					if ( is_array( $value ) ) {
						$value[ $v_key ] = $f_labels[ $opt ];
					} else {
						$value = $f_labels[ $opt ];
					}
				}
				unset( $v_key, $val );
			}
		}

		return $value;
	}

	/**
	 * Trigger from the frm_display_value_atts hook
	 *
	 * @since 2.0
	 */
	public static function display_value_atts( $atts, $field ) {
		if ( $field->type == 'file' ) {
			$atts['truncate'] = false;
			$atts['html'] = true;
		} elseif ( FrmProImages::has_image_options( $field ) ) {
			$atts['truncate']      = false;
			$atts['show_filename'] = false;

			if ( isset( $atts['show_icon'] ) && ! $atts['show_icon'] ) {
				// For the CSV export.
				$atts['show_image'] = false;
				$atts['sep'] = ', ';
			} elseif ( ! isset( $atts['saved_value'] ) || ! $atts['saved_value'] ) {
				$atts['sep'] = ' ';
			}
		}

		return $atts;
	}

	public static function filter_display_value( $value, $field, $atts = array() ) {
		self::set_display_atts( $field, $atts );

		if ( $atts['type'] === 'return_raw' ) {
			return $value;
		} elseif ( $atts['type'] == 'data' ) {
			self::get_dynamic_value_for_display( $field, $atts, $value );
		} else {
			$atts['return_array'] = true;
			$value = FrmFieldsHelper::get_unfiltered_display_value( compact( 'value', 'field', 'atts' ) );

			$value = self::get_option_label_for_saved_value( $value, $field, $atts );
			if ( is_array( $value ) ) {
				$sep   = isset( $atts['sep'] ) ? $atts['sep'] : ', ';
				$value = implode( $sep, $value );
			}
		}

		if ( ! $atts['keepjs'] ) {
			FrmAppHelper::sanitize_value( 'wp_kses_post', $value );
		}

		return $value;
	}

	/**
	 * Set a value after all other field-specific formating has been set.
	 *
	 * @since 4.06.01
	 */
	public static function display_value( $value, $field, $atts ) {
		$value = FrmProCurrencyHelper::maybe_format_currency( $value, $field, $atts );
		return $value;
	}

	private static function set_display_atts( $field, &$atts ) {
		$defaults = array( 'html' => 0, 'type' => $field->type, 'keepjs' => 0 );
		$atts = array_merge( $defaults, $atts );

		if ( FrmField::is_image( $field ) ) {
			$atts['html'] = true;
			$atts['sep']  = '';
		} elseif ( isset( $atts['show'] ) && empty( $atts['show'] ) ) {
			unset( $atts['show'] );
		}

		if ( $atts['type'] == 'file' && $atts['html'] && $atts['sep'] == ', ' ) {
			$atts['sep'] = '';
			$atts['show_image'] = true;
			if ( ! isset( $atts['add_link'] ) ) {
				$atts['add_link'] = true;
			}
		}
	}

	private static function get_dynamic_value_for_display( $field, $atts, &$value ) {
		if ( ! is_numeric( $value ) ) {
			if ( ! is_array( $value ) ) {
				$value = explode( $atts['sep'], $value );
			}

			if ( is_array( $value ) ) {
				$new_value = '';
				foreach ( $value as $entry_id ) {
					if ( ! empty( $new_value ) ) {
						$new_value .= $atts['sep'];
					}

					if ( is_numeric( $entry_id ) ) {
						$new_value .= FrmProFieldsHelper::get_data_value( $entry_id, $field, $atts );
					} else {
						$new_value .= $entry_id;
					}
				}
				$value = $new_value;
			}
		} else {
			//replace item id with specified field
			$new_value = FrmProFieldsHelper::get_data_value( $value, $field, $atts );

			if ( FrmProField::is_list_field( $field ) ) {
				$linked_field = FrmField::getOne( $field->field_options['form_select'] );
				if ( $linked_field && $linked_field->type == 'file' ) {
					$old_value = explode( ', ', $new_value );
					$new_value = '';
					foreach ( $old_value as $v ) {
						$new_value .= '<img src="' . esc_url( $v ) . '" class="frm_image_from_url" alt="" />';
						if ( $atts['show_filename'] ) {
							$new_value .= '<br/>' . $v;
						}
						unset( $v );
					}
				} else {
					$new_value = $value;
				}
			}

			$value = $new_value;
		}
	}

	public static function route( $action ) {
		add_filter( 'frm_entry_stop_action_route', '__return_true' );

		add_action( 'frm_load_form_hooks', 'FrmHooksController::trigger_load_form_hooks' );
		FrmAppHelper::trigger_hook_load( 'form' );

		if ( in_array( $action, array( 'create', 'edit', 'update', 'duplicate', 'new' ) ) ) {
			wp_enqueue_style( 'formidable' );
		}

        switch ( $action ) {
            case 'create':
            case 'edit':
            case 'update':
			case 'duplicate':
				return self::$action();

            case 'new':
                return self::new_entry();

            default:
				$action = FrmAppHelper::get_param( 'action', '', 'get', 'sanitize_text_field' );
                if ( $action == -1 ) {
					$action = FrmAppHelper::get_param( 'action2', '', 'get', 'sanitize_title' );
                }

                if ( strpos($action, 'bulk_') === 0 ) {
                    FrmAppHelper::remove_get_action();
                    return self::bulk_actions($action);
				}

				$message = '';
				$errors  = array();
				switch ( FrmAppHelper::get_param( 'message' ) ) {
					case 'destroy_all':
						$message = __( 'Entries Successfully Deleted', 'formidable-pro' );
						break;

					case 'no_entries_selected':
						$errors[] = __( 'No Entries Selected', 'formidable-pro' );
						break;
				}

                return FrmEntriesController::display_list( $message, $errors );
        }
    }

    /**
     * @return string The name of the entry listing class
     */
	public static function list_class() {
		return 'FrmProEntriesListHelper';
	}

	public static function manage_columns( $columns ) {
        global $frm_vars;
        $form_id = FrmForm::get_current_form_id();

		$cb_item = array( 'cb' => '<input type="checkbox" />' );
		$columns = $cb_item + (array) $columns;
		$columns[ $form_id . '_post_id' ] = __( 'Post', 'formidable-pro' );
		$columns[ $form_id . '_is_draft' ] = __( 'Draft', 'formidable-pro' );
		$columns[ $form_id . '_parent_item_id' ] = __( 'Parent Entry ID', 'formidable-pro' );

        $frm_vars['cols'] = $columns;

        return $columns;
    }

	public static function row_actions( $actions, $item ) {
		$edit_link = FrmProEntry::admin_edit_link( $item->id );
		if ( current_user_can('frm_edit_entries') ) {
			$actions['edit'] = '<a href="' . esc_url( $edit_link ) . '">' . __( 'Edit' ) . '</a>';
		}

        if ( current_user_can('frm_create_entries') ) {
			$duplicate_link = '?page=formidable-entries&frm_action=duplicate&id=' . $item->id . '&form=' . $item->form_id;
			$actions['duplicate'] = '<a href="' . esc_url( wp_nonce_url( $duplicate_link ) ) . '">' . __( 'Duplicate', 'formidable-pro' ) . '</a>';
        }

        // move delete link to the end of the links
        if ( isset($actions['delete']) ) {
            $delete_link = $actions['delete'];
            unset($actions['delete']);
            $actions['delete'] = $delete_link;
        }

        return $actions;
    }

	public static function get_form_results( $atts ) {
		FrmAppHelper::sanitize_value( 'wp_kses_post', $atts );

        $atts = shortcode_atts(
			array(
				'id'         => false, 'cols' => 99, 'style' => true,
				'fields'     => false, 'clickable' => false, 'user_id' => false,
				'google'     => false, 'pagesize' => 20, 'sort' => true,
				'edit_link'  => false, 'delete_link' => false, 'page_id' => false,
				'no_entries' => __( 'No Entries Found', 'formidable-pro' ),
				'confirm'    => __( 'Are you sure you want to delete that entry?', 'formidable-pro' ),
				'drafts'     => '0',
			),
			$atts
		);

		$atts['form'] = self::get_form( $atts );
		if ( ! $atts['form'] ) {
			return;
		}

        if ( $atts['fields'] ) {
            $atts['fields'] = explode( ',', $atts['fields'] );
		}

		self::get_table_values( $atts );
		if ( empty( $atts['form_cols'] ) ) {
			$contents = '<div class="frm_no_entries">' . __( 'There are no matching fields. Please check your formresults shortcode to make sure you are using the correct form and field IDs.', 'formidable-pro' ) . '</div>';
			return $contents;
		}

        $contents = '';
		self::add_delete_entry_message( $atts, $contents );
		self::setup_edit_link( $atts );
		self::setup_delete_link( $atts );

		$filename = self::set_formresults_filename( $atts );

		self::load_form_scripts( $atts );

        ob_start();
		include( FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/' . $filename . '.php' );
        $contents .= ob_get_contents();
        ob_end_clean();

        if ( ! $atts['google'] && $atts['clickable'] ) {
			$contents = make_clickable( $contents );
        }

        return $contents;
    }

	/**
	* Get the form for the formresults table
	*
	* @since 2.0.09
	* @param array $atts
	* @return object
	*/
	private static function get_form( $atts ) {
        if ( ! $atts['id'] ) {
            return false;
        }

		return FrmForm::getOne( $atts['id'] );
	}

	/**
	* Get entries and fields for formresults
	*
	* @since 2.0.09
	* @param array $atts
	*/
	private static function get_table_values( &$atts ) {
		// Get all fields in the form
		$atts['form_cols'] = FrmField::get_all_for_form( $atts['form']->id, '', 'include' );

		// Get all entries for the form
		$atts['entries'] = self::get_entries_for_table( $atts );

		$subforms_to_include = array();
		$field_count = 0;
		foreach ( $atts['form_cols'] as $k => $f ) {
			if ( $field_count < $atts['cols'] && self::is_field_needed( $f, $atts, $subforms_to_include ) ) {
				$field_count++;
				self::get_sub_field_values( $f, $atts );
			} else {
				unset( $atts['form_cols'][ $k ] );
			}
		}
	}

	private static function get_entries_for_table( $atts ) {
		$where = array( 'it.form_id' => $atts['form']->id );

		if ( $atts['drafts'] != 'both' ) {
			$where['it.is_draft'] = (int) $atts['drafts'];
		}

		if ( $atts['user_id'] ) {
			$where['user_id'] = (int) FrmAppHelper::get_user_id_param( $atts['user_id'] );
		}

		$s = FrmAppHelper::get_param( 'frm_search', false, 'get', 'sanitize_text_field' );
		if ( $s ) {
			$new_ids = FrmProEntriesHelper::get_search_ids( $s, $atts['form']->id, array( 'is_draft' => $atts['drafts'] ) );
			$where['it.id'] = $new_ids;
		}

		if ( isset( $new_ids ) && empty( $new_ids ) ) {
			$entries = false;
		} else {
			$entries = FrmEntry::getAll( $where, '', '', true, false );
		}

		return $entries;
	}

	/**
	* Check if each field is needed in the formresults table
	*
	* @since 2.0.09
	* @param object $f - field
	* @param array $atts
	* @param array $subforms_to_include
	* @return boolean
	*/
	private static function is_field_needed( $f, $atts, &$subforms_to_include ) {
		if ( ! empty( $atts['fields'] ) ) {
			if ( FrmField::is_no_save_field( $f->type ) ) {
				if ( FrmField::is_option_true( $f, 'form_select' ) && ( in_array( $f->id, $atts['fields'] ) || in_array( $f->field_key, $atts['fields'] ) ) ) {
					$subforms_to_include[] = $f->field_options['form_select'];
				}
				return false;
			}

			if ( ! in_array( $f->form_id, $subforms_to_include ) && ! in_array( $f->id, $atts['fields'] ) && ! in_array( $f->field_key, $atts['fields'] ) ) {
				return false;
			}
		} else {
			if ( FrmField::is_no_save_field( $f->type ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	* Get values in nested forms (repeating sections and embed form)
	*
	* @since 2.0.09
	* @param object $field
	* @param array $atts
	*/
	private static function get_sub_field_values( $field, &$atts ) {
		if ( empty( $atts['entries'] ) ) {
			return;
		}

		foreach ( $atts['entries'] as $key => $entry ) {
			if ( ! isset( $entry->metas[ $field->id ] ) || $entry->metas[ $field->id ] == '' ) {
				FrmProEntryMeta::add_repeating_value_to_entry( $field, $atts['entries'][ $key ] );
			}
		}
	}

	/**
	 * If delete_link is set in formresults and frm_action is set to destroy,
	 * check if entry should be deleted when page is loaded
	 */
	private static function add_delete_entry_message( $atts, &$contents ) {
		$action = FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' );
		if ( $atts['delete_link'] && $action == 'destroy' ) {
			$delete_message = self::ajax_destroy( false, false, false );
			$delete_message = '<div class="' . esc_attr( $atts['style'] ? FrmFormsHelper::get_form_style_class() : '' ) . '"><div class="frm_message">' . $delete_message . '</div></div>';
			$contents = $delete_message;
		}
	}

	/**
	* If edit link is set in formresults, set up values for the edit link
	*
	* @since 2.0.09
	* @param array $atts
	*/
	private static function setup_edit_link( &$atts ) {
		if ( $atts['edit_link'] ) {
			$atts['anchor'] = '';
			if ( ! $atts['page_id'] ) {
				global $post;
				$atts['page_id'] = $post ? $post->ID : 0;
				$atts['anchor'] = '#form_' . $atts['form']->form_key;
			}
			if ( $atts['edit_link'] === '1' ) {
				$atts['edit_link'] = __( 'Edit', 'formidable-pro' );
			}
			$atts['permalink'] = get_permalink( $atts['page_id'] );
		}
	}

	/**
	* If delete_link is set to true in formresults, set the delete link text
	*
	* @since 2.0.09
	* @param array $atts
	*/
	private static function setup_delete_link( &$atts ) {
		if ( $atts['delete_link'] === '1' ) {
			$atts['delete_link'] = __( 'Delete', 'formidable-pro' );
		}
	}

	/**
	* Get the filename for the formresults table
	*
	* @since 2.0.09
	* @param array $atts
	* @return string $filename
	*/
	private static function set_formresults_filename( &$atts ) {
		if ( $atts['google'] ) {
			$filename = 'google_table';
			self::prepare_google_table( $atts );
		} else {
			$atts['fields'] = (array) $atts['fields'];
			$filename = 'table';
		}
		return $filename;
	}

	private static function prepare_google_table( $atts ) {
		global $frm_vars;

		$options = array(
			'allowHtml' => true,
			'sort'      => $atts['sort'] ? 'enable' : 'disable',
		);

		if ( $atts['pagesize'] ) {
			$options['page']     = 'enable';
			$options['pageSize'] = (int) $atts['pagesize'];
		}

		if ( $atts['style'] ) {
			$options['cssClassNames'] = array( 'oddTableRow' => 'frm_even' );
		}

		$shortcode_options = $atts;
		$shortcode_options['form_id'] = $atts['form']->id;
		unset( $shortcode_options['entries'], $shortcode_options['form_cols'], $shortcode_options['form'] );
		unset( $shortcode_options['permalink'], $shortcode_options['anchor'] );

		$graph_vals = array(
			'fields'    => array(),
			'entries'   => array(),
			'options'   => $shortcode_options,
			'graphOpts' => $options,
		);

		if ( $atts['clickable'] ) {
			$graph_vals['options']['no_entries'] = make_clickable( $graph_vals['options']['no_entries'] );
		}

		if ( ! isset( $atts['entries'] ) || empty( $atts['entries'] ) ) {
			$atts['entries'] = array();
		}

		$first_loop = true;
		foreach ( $atts['entries'] as $k => $entry ) {
			$this_entry = array(
				'id'    => $entry->id,
				'metas' => array(),
			);

			foreach ( $atts['form_cols'] as $col ) {
				$field_value = isset( $entry->metas[ $col->id ] ) ? $entry->metas[ $col->id ] : false;
				$type = $col->type;

				$val = FrmEntriesHelper::display_value(
					$field_value,
					$col,
					array(
						'type'          => $type,
						'post_id'       => $entry->post_id,
						'entry_id'      => $entry->id,
						'show_filename' => false,
					)
				);

				if ( $col->type == 'number' ) {
					$val = empty( $val ) ? '0' : $val;
					if ( ! is_numeric( $val ) ) {
						// Repeaters my not be numeric.
						$type = 'text';
					}
				} elseif ( $col->type == 'checkbox' && count( $col->options ) == 1 ) {
					// force boolean values
					$val = empty( $val ) ? false : true;
				} else if ( empty( $val ) ) {
					$val = '';
				} else {
					$val = ( $atts['clickable'] && $col->type != 'file' ) ? make_clickable( $val ) : $val;
				}

				$this_entry['metas'][ $col->id ] = $val;

				if ( $first_loop ) {
					// add the fields to graphs on first loop only
					$graph_vals['fields'][] = array(
						'id'        => $col->id,
						'type'      => $type,
						'name'      => $col->name,
						'options'   => $col->options,
						'field_options' => array( 'post_field' => isset( $col->field_options['post_field'] ) ? $col->field_options['post_field'] : '' ),
					);
				}
				unset( $col );
			}

			if ( $atts['edit_link'] && FrmProEntriesHelper::user_can_edit( $entry, $atts['form'] ) ) {
				$this_entry['editLink'] = esc_url_raw( add_query_arg( array( 'frm_action' => 'edit', 'entry' => $entry->id ), $atts['permalink'] ) ) . $atts['anchor'];
			}

			if ( $atts['delete_link'] && FrmProEntriesHelper::user_can_delete( $entry ) ) {
				$this_entry['deleteLink'] = esc_url_raw( add_query_arg( array( 'frm_action' => 'destroy', 'entry' => $entry->id ) ) );
			}
			$graph_vals['entries'][] = $this_entry;

			$first_loop = false;
			unset( $k, $entry, $this_entry );
		}

		if ( ! isset( $frm_vars['google_graphs'] ) ) {
			$frm_vars['google_graphs'] = array();
		}

		if ( ! isset( $frm_vars['google_graphs']['table'] ) ) {
			$frm_vars['google_graphs']['table'] = array();
		}

		$frm_vars['google_graphs']['table'][] = $graph_vals;
	}

	/**
	* Load JS and CSS for a shortcode
	*/
	private static function load_form_scripts( $atts = array() ) {
		global $frm_vars;

		// Trigger CSS loading
		if ( isset( $atts['style'] ) && $atts['style'] ) {
		    $frm_vars['load_css'] = true;
		}

		// Trigger the js load
		$frm_vars['forms_loaded'][] = true;
	}


	public static function get_search( $atts ) {
        $atts = shortcode_atts(
			array(
				'post_id' => '',
				'label'   => __( 'Search', 'formidable-pro' ),
				'style'   => false,
				'views'   => '',
			),
			$atts
		);

        if ( $atts['post_id'] == '' ) {
            global $post;
			if ( $post ) {
                $atts['post_id'] = $post->ID;
			}
        }

        if ( $atts['post_id'] != '' ) {
            $action_link = get_permalink($atts['post_id']);
        } else {
            $action_link = '';
        }

        if ( ! empty($atts['style']) ) {
			self::load_form_scripts();

            if ( $atts['style'] == 1 || 'true' == $atts['style'] ) {
                $atts['style'] = FrmStylesController::get_form_style_class('with_frm_style', 'default');
            } else {
                $atts['style'] .= ' with_frm_style';
            }
        }

        ob_start();
        include(FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/search.php');
        $contents = ob_get_contents();
        ob_end_clean();
        return $contents;
    }

    public static function entry_link_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'id'          => false,
				'field_key'   => 'created_at',
				'type'        => 'list',
				'logged_in'   => true,
				'edit'        => true,
				'class'       => '',
				'link_type'   => 'page',
				'blank_label' => '',
				'param_name'  => 'entry',
				'param_value' => 'key',
				'page_id'     => false,
				'show_delete' => false,
				'confirm'     => __( 'Are you sure you want to delete that entry?', 'formidable-pro' ),
				'drafts'      => false,
				'order'       => '',
				'user_id'     => 'current',
			),
			$atts
		);

		// Keep logged_in for reverse compatibility
		if ( $atts['logged_in'] == false ) {
			$atts['user_id'] = false;
		}

        $user_ID = get_current_user_id();
		if ( ! $atts['id'] || ( $atts['user_id'] && ! $user_ID ) ) {
            return;
        }

        $atts = self::fill_entry_links_atts($atts);

        $action = ( isset($_GET) && isset($_GET['frm_action']) ) ? 'frm_action' : 'action';
		$entry_action = FrmAppHelper::simple_get( $action, 'sanitize_title' );
		$entry_key = FrmAppHelper::simple_get( 'entry', 'sanitize_title' );

        if ( $entry_action == 'destroy' ) {
            self::maybe_delete_entry($entry_key);
        }

        $entries = self::get_entry_link_entries( $atts );
        if ( empty($entries) ) {
            return;
        }

		$extra_args = array(
			'entry_action' => $entry_action,
			'entry_key' => $entry_key,
			'current_user' => $user_ID,
		);
		self::maybe_remove_entries_from_list( $extra_args, $atts, $entries );

        $content = array();
		switch ( $atts['type'] ) {
			case 'list':
				self::entry_link_list( $entries, $atts, $content );
				break;
			case 'select':
				self::entry_link_select( $entries, $atts, $content );
				break;
			case 'collapse':
				self::entry_link_collapse( $entries, $atts, $content );
		}

        $content = implode('', $content);
        return $content;
    }

	private static function fill_entry_links_atts( $atts ) {
        $atts['id'] = (int) $atts['id'];
        if ( $atts['show_delete'] === 1 ) {
            $atts['show_delete'] = __( 'Delete', 'formidable-pro' );
        }
        $atts['label'] = $atts['show_delete'];

        $atts['field'] = false;
        if ( $atts['field_key'] != 'created_at' ) {
            $atts['field'] = FrmField::getOne($atts['field_key']);
            if ( ! $atts['field'] ) {
                $atts['field_key'] = 'created_at';
            }
        }

		if ( ! in_array( $atts['type'], array( 'list', 'collapse', 'select' ) ) ) {
            $atts['type'] = 'select';
        }

		if ( empty( $atts['confirm'] ) ) {
			 $atts['confirm'] = __( 'Are you sure you want to delete that entry?', 'formidable-pro' );
		}

		if ( $atts['user_id'] == 'current' ) {
			$atts['user_id'] = get_current_user_id();
		}

        global $post;
        $atts['permalink'] = get_permalink( $atts['page_id'] ? $atts['page_id'] : $post->ID );

        return $atts;
    }

	private static function get_entry_link_entries( $atts ) {
		$s = FrmAppHelper::get_param( 'frm_search', false, 'get', 'sanitize_text_field' );

        if ( $s ) {
			$entry_ids = FrmProEntriesHelper::get_search_ids( $s, $atts['id'], array( 'is_draft' => $atts['drafts'], 'user_id' => $atts['user_id'] ) );
        } else {
			$entry_ids = FrmEntryMeta::getEntryIds( array( 'fi.form_id' => (int) $atts['id'] ), '', '', true, array( 'is_draft' => $atts['drafts'], 'user_id' => $atts['user_id'] ) );
        }

        if ( empty($entry_ids) ) {
            return;
        }

		$order = strpos( strtolower( trim( $atts['order'] ) ), 'order ' ) === 0 ? $atts['order'] : '';
		$order = ( $atts['type'] == 'collapse' || $atts['order'] == 'DESC' ) ? ' ORDER BY it.created_at DESC' : $order;

        $entries = FrmEntry::getAll( array( 'it.id' => $entry_ids ), $order, '', true);

        return $entries;
    }

	/**
	* Remove deleted entries from the list.
	* Also remove private, draft, and pending posts if the current user is not the creator or an administrator.
	*
	* @since 2.0.18
	* @param array $extra_args
	* @param array $atts
	* @param array $entries
	*/
	private static function maybe_remove_entries_from_list( $extra_args, $atts, &$entries ) {
		$public_entries = array();
		$post_status_check = array();

		foreach ( $entries as $k => $entry ) {
			// If entry was just deleted, don't show it in list
			if ( $extra_args['entry_action'] == 'destroy' && in_array( $extra_args['entry_key'], array( $entry->item_key, $entry->id ) ) ) {
				continue;
			}

			// If entry has a post, check the post status
			if ( $entry->post_id ) {
				$post_status_check[ $entry->post_id ] = $entry->id;
			}
			$public_entries[ $entry->id ] = $entry;
		}

		$current_user_is_creator_of_all_listed_entries = ( $extra_args['current_user'] && $atts['user_id'] == $extra_args['current_user'] );
		if ( current_user_can( 'administrator' ) || $current_user_is_creator_of_all_listed_entries ) {
			// If the current user is an administrator or the creator of the entry, don't remove private, draft, or pending posts
		} else if ( ! empty( $post_status_check ) ) {
			global $wpdb;
			$query = array( 'post_status !' => 'publish', 'ID' => array_keys( $post_status_check ) );
			$remove_entries = FrmDb::get_col( $wpdb->posts, $query, 'ID' );
			unset($query);

			foreach ( $remove_entries as $entry_post_id ) {
				unset( $public_entries[ $post_status_check[ $entry_post_id ] ] );
			}
			unset( $remove_entries );
		}

		$entries = $public_entries;
	}

	private static function entry_link_list( $entries, $atts, array &$content ) {
		$content[] = '<ul class="frm_entry_ul ' . $atts['class'] . '">' . "\n";

        foreach ( $entries as $entry ) {
            $value = self::entry_link_meta_value($entry, $atts);
            $link = self::entry_link_href($entry, $atts);

			$content[] = '<li><a href="' . esc_url( $link ) . '">' . $value . '</a>';
            if ( ! empty( $atts['show_delete'] ) && FrmProEntriesHelper::user_can_delete( $entry ) ) {
				$content[] = ' <a href="' . esc_url( add_query_arg( array( 'frm_action' => 'destroy', 'entry' => $entry->id ), $atts['permalink'] ) ) . '" class="frm_delete_list" data-frmconfirm="' . esc_attr( $atts['confirm'] ) . '">' . $atts['show_delete'] . '</a>' . "\n";
            }
            $content[] = "</li>\n";
        }

        $content[] = "</ul>\n";
    }

	private static function entry_link_collapse( $entries, $atts, array &$content ) {
		FrmProStylesController::enqueue_jquery_css();
        wp_enqueue_script('jquery-ui-core');
        wp_enqueue_script('formidable' );
		wp_enqueue_script('formidablepro');

        $content[]  = '<div class="frm_collapse">';
		$year       = '';
		$month      = '';
		$prev_year  = false;
		$prev_month = false;

        foreach ( $entries as $entry ) {
            $value = self::entry_link_meta_value($entry, $atts);
            $link  = self::entry_link_href($entry, $atts);

			$timestamp = strtotime( $entry->created_at );
            $new_year  = date_i18n( 'Y', $timestamp );
            $new_month = date_i18n( 'F', $timestamp );
            if ( $new_year != $year ) {
                if ( $prev_year ) {
                    if ( $prev_month ) {
                        $content[] = '</ul></div>';
                    }
                    $content[]  = '</div>';
                    $prev_month = false;
                }
				$class     = $prev_year ? ' frm_hidden' : '';
                $triangle  = $prev_year ? 'e' : 's';
				$content[] = "\n" . '<div class="frm_year_heading frm_year_heading_' . esc_attr( $atts['id'] ) . '">
					<span class="ui-icon ui-icon-triangle-1-' . esc_attr( $triangle ) . '"></span>' . "\n" .
                    '<a>' . sanitize_text_field( $new_year ) . '</a></div>' . "\n" .
					'<div class="frm_toggle_container' . esc_attr( $class ) . '">' . "\n";
                $prev_year = true;
            }

            if ( $new_month != $month ) {
                if ( $prev_month ) {
                    $content[] = '</ul></div>';
                }
				$class      = $prev_month ? ' frm_hidden' : '';
                $triangle   = $prev_month ? 'e' : 's';
				$content[]  = '<div class="frm_month_heading frm_month_heading_' . esc_attr( $atts['id'] ) . '">
					<span class="ui-icon ui-icon-triangle-1-' . esc_attr( $triangle ) . '"></span>' . "\n" .
					'<a>' . sanitize_text_field( $new_month ) . '</a>' . "\n" . '</div>' . "\n" .
					'<div class="frm_toggle_container frm_month_listing' . esc_attr( $class ) . '"><ul>' . "\n";
                $prev_month = true;
            }
			$content[] = '<li><a href="' . esc_url( $link ) . '">' . $value . '</a>';

            if ( $atts['show_delete'] && FrmProEntriesHelper::user_can_delete($entry) ) {
				$content[] = ' <a href="' . esc_url( add_query_arg( array( 'frm_action' => 'destroy', 'entry' => $entry->id ), $atts['permalink'] ) ) . '" class="frm_delete_list" data-frmconfirm="' . esc_attr( $atts['confirm'] ) . '">' . $atts['show_delete'] . '</a>' . "\n";
            }
            $content[] = "</li>\n";
            $year  = $new_year;
            $month = $new_month;
        }

        if ( $prev_year ) {
            $content[] = '</div>';
        }
        if ( $prev_month ) {
            $content[] = '</ul></div>';
        }
        $content[] = '</div>';
    }

	private static function entry_link_select( $entries, $atts, array &$content ) {
        global $post;

		$content[] = '<select id="frm_select_form_' . esc_attr( $atts['id'] ) . '" name="frm_select_form_' . esc_attr( $atts['id'] ) . '" class="' . esc_attr( $atts['class'] ) . '" onchange="location=this.options[this.selectedIndex].value;">' . "\n";
		$content[] = '<option value="' . esc_attr( get_permalink( $post->ID ) ) . '">' . $atts['blank_label'] . '</option>' . "\n";
		$entry_param = FrmAppHelper::simple_get( 'entry', 'sanitize_title' );

        foreach ( $entries as $entry ) {
            $value = self::entry_link_meta_value($entry, $atts);
            $link = self::entry_link_href($entry, $atts);

			$content[] = '<option value="' . esc_url( $link ) . '" ' . selected( $entry_param, $entry->item_key, false ) . '>' . esc_attr($value) . "</option>\n";
        }

        $content[] = "</select>\n";
        if ( $atts['show_delete'] && $entry_param ) {
			$content[] = " <a href='" . esc_url( add_query_arg( array( 'frm_action' => 'destroy', 'entry' => $entry_param ), $atts['permalink'] ) ) . "' class='frm_delete_list' data-frmconfirm='" . esc_attr( $atts['confirm'] ) . "'>" . $atts['show_delete'] . "</a>\n";
        }
    }

	private static function entry_link_meta_value( $entry, $atts ) {
        $value = '';

        if ( $atts['field_key'] && $atts['field_key'] != 'created_at' ) {
            if ( $entry->post_id && ( ( $atts['field'] && $atts['field']->field_options['post_field'] ) || $atts['field']->type == 'tag' ) ) {
                $meta = false;
                $value = FrmProEntryMetaHelper::get_post_value(
					$entry->post_id,
					$atts['field']->field_options['post_field'],
					$atts['field']->field_options['custom_field'],
                    array(
                        'type' => $atts['field']->type, 'form_id' => $atts['field']->form_id, 'field' => $atts['field'],
                    )
                );
            } else {
				$meta = isset( $entry->metas[ $atts['field']->id ] ) ? $entry->metas[ $atts['field']->id ] : '';
            }
        } else {
            $meta = reset($entry->metas);
        }

        self::entry_link_value($entry, $atts, $meta, $value);

        return $value;
    }

	private static function entry_link_value( $entry, $atts, $meta, &$value ) {
        if ( 'created_at' != $atts['field_key'] && $meta ) {
            if ( is_object($meta) ) {
                $value = $meta->meta_value;
            } else {
                $value = $meta;
            }
        }

        if ( '' == $value ) {
            $value = date_i18n(get_option('date_format'), strtotime($entry->created_at));
            return;
        }

		$new_atts = array(
			'type'          => $atts['field']->type,
			'display_type'  => $atts['type'],
			'show_filename' => false,
		);

		$value = FrmEntriesHelper::display_value( $value, $atts['field'], $new_atts );
    }

	private static function entry_link_href( $entry, $atts ) {
        $args = array(
            $atts['param_name'] => ( 'key' == $atts['param_value'] ) ? $entry->item_key : $entry->id,
        );

        if ( $atts['edit'] ) {
            $args['frm_action'] = 'edit';
        }

        if ( $atts['link_type'] === 'scroll' ) {
			$link = '#' . $entry->item_key;
        } elseif ( $atts['link_type'] === 'admin' ) {
			$link = add_query_arg( $args, FrmAppHelper::get_server_value( 'REQUEST_URI' ) );
        } else {
            $link = add_query_arg($args, $atts['permalink']);
        }

        return $link;
    }

	public static function entry_edit_link( $atts ) {
        global $post, $frm_vars, $wpdb;
		$atts = shortcode_atts(
			array(
				'id'             => ( isset( $frm_vars['editing_entry'] ) ? $frm_vars['editing_entry'] : false ),
				'label'          => __( 'Edit', 'formidable-pro' ),
				'cancel'         => __( 'Cancel', 'formidable-pro' ),
				'class'          => '',
				'page_id'        => ( $post ? $post->ID : 0 ),
				'html_id'        => false,
				'prefix'         => '',
				'form_id'        => false,
				'title'          => '',
				'fields'         => array(),
				'exclude_fields' => array(),
				'start_page'     => 1,
			),
			$atts
		);

        $link = '';
		$entry_id = ( $atts['id'] && is_numeric( $atts['id'] ) ) ? $atts['id'] : FrmAppHelper::get_param( 'entry', false, 'get', 'sanitize_text_field' );

        if ( ! $entry_id && $atts['id'] === 'current' ) {
            if ( ! empty( $frm_vars['editing_entry'] ) && is_numeric( $frm_vars['editing_entry'] ) ) {
                $entry_id = $frm_vars['editing_entry'];
            } elseif ( $post ) {
				$entry_id = FrmDb::get_var( $wpdb->prefix . 'frm_items', array( 'post_id' => $post->ID ) );
            }
        }

        if ( ! $entry_id ) {
            return '';
        }

        if ( ! $atts['form_id'] ) {
			$atts['form_id'] = (int) FrmDb::get_var( $wpdb->prefix . 'frm_items', array( 'id' => $entry_id ), 'form_id' );
        }

        //if user is not allowed to edit, then don't show the link
        if ( ! FrmProEntriesHelper::user_can_edit($entry_id, $atts['form_id']) ) {
            return $link;
        }

        if ( empty($atts['prefix']) ) {
			$link = add_query_arg( array( 'frm_action' => 'edit', 'entry' => $entry_id ), get_permalink( $atts['page_id'] ) );

			if ( $atts['label'] ) {
				$link = '<a href="' . esc_url( $link ) . '" class="' . esc_attr( $atts['class'] ) . '">' . $atts['label'] . '</a>';
			}

			return $link;
		}

		$action = ( $_POST && isset( $_POST['frm_action'] ) ) ? 'frm_action' : 'action';
		$form_action = FrmAppHelper::get_post_param( $action, '', 'sanitize_title' );
		$posted_form_id = FrmAppHelper::get_post_param( 'form_id', '', 'sanitize_title' );
		$posted_entry_id = FrmAppHelper::get_post_param( 'id', '', 'sanitize_title' );

		if ( $form_action == 'update' && $posted_form_id == $atts['form_id'] && $posted_entry_id == $entry_id ) {
			$errors = ( isset( $frm_vars['created_entries'][ $atts['form_id'] ] ) && isset( $frm_vars['created_entries'][ $atts['form_id'] ]['errors'] ) ) ? $frm_vars['created_entries'][ $atts['form_id'] ]['errors'] : array();

            if ( ! empty($errors) ) {
				return FrmFormsController::get_form_shortcode( array( 'id' => $atts['form_id'], 'entry_id' => $entry_id, 'fields' => $atts['fields'], 'exclude_fields' => $atts['exclude_fields'] ) );
            }

			$link .= "<script type='text/javascript'>document.addEventListener('DOMContentLoaded',function(){frmFrontForm.scrollToID('" . esc_js( $atts['prefix'] . $entry_id ) . "');});</script>";
        }

        if ( empty($atts['title']) ) {
            $atts['title'] = $atts['label'];
        }

        if ( ! $atts['html_id'] ) {
			$atts['html_id'] = 'frm_edit_' . $entry_id;
        }

		self::load_form_scripts();

		$data = array(
			'entryid'   => $entry_id,
			'prefix'    => $atts['prefix'],
			'pageid'    => $atts['page_id'],
			'formid'    => $atts['form_id'],
			'cancel'    => $atts['cancel'],
			'edit'      => $atts['label'],
			'startpage' => $atts['start_page'],
		);
		if ( ! empty( $atts['fields'] ) ) {
			$data['fields'] = implode( ',', (array) $atts['fields'] );
		}
		if ( ! empty( $atts['exclude_fields'] ) ) {
			$data['exclude_fields'] = implode( ',', (array) $atts['exclude_fields'] );
		}

		$link .= '<span class="frm_edit_link_container">';
		$link .= '<a href="#" class="frm_inplace_edit frm_edit_link ' . esc_attr( $atts['class'] ) . '" id="' . esc_attr( $atts['html_id'] ) . '" title="' . esc_attr( $atts['title'] ) . '"';
		foreach ( $data as $name => $label ) {
			$link .= ' data-' . str_replace( '_', '', sanitize_title( $name ) ) . '="' . esc_attr( $label ) . '"';
		}
		$link .= '>' . wp_kses_post( $atts['label'] ) . "</a>\n";
		$link .= '</span>';

        return $link;
    }

	public static function entry_update_field( $atts ) {
		global $frm_vars, $frm_update_link_count;

		$atts = shortcode_atts(
			array(
				'id'       => ( isset( $frm_vars['editing_entry'] ) ? $frm_vars['editing_entry'] : false ),
				'field_id' => false,
				'label'    => __( 'Update', 'formidable-pro' ),
				'class'    => '',
				'value'    => '',
				'message'  => '',
				'title'    => '',
			),
			$atts
		);

		if ( ! $atts['field_id'] ) {
			return __( 'You are missing options in your shortcode. A field_id is required.', 'formidable-pro' );
		}

		$entry_id = ( $atts['id'] && is_numeric( $atts['id'] ) ) ? absint( $atts['id'] ) : FrmAppHelper::get_param( 'entry', false, 'get', 'absint' );
		if ( ! $entry_id ) {
			return '';
		}

		$field = FrmField::getOne( $atts['field_id'] );
		if ( ! $field || ! FrmProEntriesHelper::user_can_edit( $entry_id, $field->form_id ) ) {
			return '';
		}

		// Check if current value is equal to new value
		$current_val = FrmProEntryMetaHelper::get_post_or_meta_value( $entry_id, $field );
		if ( $current_val == $atts['value'] ) {
			return '';
		}

		self::load_form_scripts();

		if ( ! $frm_update_link_count ) {
			$frm_update_link_count = 0;
		}

		$frm_update_link_count++;

		if ( empty( $atts['title'] ) ) {
			$atts['title'] = $atts['label'];
		}

		$value   = htmlspecialchars( addslashes( $atts['value'] ) );
		$message = htmlspecialchars( addslashes( $atts['message'] ) );
		$onclick = "frmUpdateField({$entry_id},{$field->id},'{$value}','{$message}',{$frm_update_link_count});return false;";

		$html_id = "frm_update_field_{$entry_id}_{$field->id}_{$frm_update_link_count}";
		$class   = esc_attr( 'frm_update_field_link ' . $atts['class'] );
		$title   = esc_attr( $atts['title'] );

		$link = "<a href=\"#\" onclick=\"{$onclick}\" id=\"{$html_id}\" class=\"{$class}\" title=\"{$title}\">{$atts['label']}</a>";

		return $link;
	}

	public static function entry_delete_link( $atts ) {
		global $post, $frm_vars;
		$atts = shortcode_atts(
			array(
				'id'      => ( isset( $frm_vars['editing_entry'] ) ? $frm_vars['editing_entry'] : false ),
				'label'   => __( 'Delete' ),
				'confirm' => __( 'Are you sure you want to delete that entry?', 'formidable-pro' ),
				'class'   => '',
				'page_id' => $post ? $post->ID : 0,
				'html_id' => false,
				'prefix'  => '',
				'title'   => '',
			),
			$atts
		);

		$entry_id = FrmAppHelper::get_param( 'id', false, 'get', 'sanitize_text_field' );
		$entry_id = ( $atts['id'] && is_numeric( $atts['id'] ) ) ? $atts['id'] : ( FrmAppHelper::is_admin() ? $entry_id : FrmAppHelper::get_param( 'entry', false, 'get', 'sanitize_text_field' ) );

		if ( empty( $entry_id ) || ! FrmProEntriesHelper::user_can_delete( $entry_id ) ) {
			// User doesn't have permission to delete this entry
            return '';
        }

		self::load_form_scripts();

        if ( ! empty($atts['prefix']) ) {
            if ( ! $atts['html_id'] ) {
				$atts['html_id'] = 'frm_delete_' . $entry_id;
            }

			$link = '<a href="#" class="frm_ajax_delete frm_delete_link ' . esc_attr( $atts['class'] ) . '" id="' . esc_attr( $atts['html_id'] ) . '" data-deleteconfirm="' . esc_attr( $atts['confirm'] ) . '" data-entryid="' . esc_attr( $entry_id ) . '" data-prefix="' . esc_attr( $atts['prefix'] ) . '">' . $atts['label'] . "</a>\n";
            return $link;
        }

        $link = '';

        // Delete entry now
		$action = FrmAppHelper::get_param( 'frm_action', '', 'get', 'sanitize_title' );
        if ( $action == 'destroy' ) {
			$entry_key = FrmAppHelper::get_param( 'entry', '', 'get', 'absint' );
			if ( $entry_key && $entry_key == $entry_id ) {
                $link = self::ajax_destroy(false, false, false);
                if ( ! empty($link) ) {
					$new_link = '<div class="frm_message">' . $link . '</div>';
                    if ( empty($atts['label']) ) {
                        return;
                    }

                    if ( $link == __( 'Your entry was successfully deleted', 'formidable-pro' ) ) {
                        return $new_link;
                    } else {
                        $link = $new_link;
                    }

                    unset($new_link);
                }
            }
        }

		$delete_link = wp_nonce_url( admin_url( 'admin-ajax.php?action=frm_entries_destroy&entry=' . $entry_id . '&redirect=' . $atts['page_id'] ), 'frm_ajax', 'nonce' );
        if ( empty($atts['label']) ) {
            $link .= $delete_link;
        } else {
            if ( empty($atts['title']) ) {
                $atts['title'] = $atts['label'];
            }
			$link .= '<a href="' . esc_url( $delete_link ) . '" class="' . esc_attr( $atts['class'] ) . '" data-frmconfirm="' . esc_attr( $atts['confirm'] ) . '" title="' . esc_attr( $atts['title'] ) . '">' . $atts['label'] . '</a>' . "\n";
        }

        return $link;
    }

	public static function get_field_value_shortcode( $sc_atts ) {
		$atts = shortcode_atts(
			array(
				'entry'        => false,
				'field_id'     => false,
				'user_id'      => false,
				'ip'           => false,
				'show'         => '',
				'format'       => '',
				'return_array' => false,
				'default'      => '',
				'truncate'     => false,
			),
			$sc_atts
		);

		// Include all user-defined atts as well
		$atts = (array) $atts + (array) $sc_atts;

		// For reverse compatibility
		if ( isset( $atts['entry_id'] ) && ! $atts['entry'] ) {
			$atts['entry'] = $atts['entry_id'];
		}

		if ( ! $atts['field_id'] ) {
			return __( 'You are missing options in your shortcode. field_id is required.', 'formidable-pro' );
		}

		$field = FrmField::getOne($atts['field_id']);
		if ( ! $field ) {
			return $atts['default'];
		}

		$entries = self::get_frm_field_value_entry( $field, $atts );

		if ( empty( $entries ) ) {
			return $atts['default'];
		}

		$truncate = $atts['truncate'] && is_numeric( $atts['truncate'] ) && 1 !== (int) $atts['truncate'] ? $atts['truncate'] : false;
		if ( $truncate ) {
			// unset the attribute to avoid double truncating from FrmEntriesHelper::display_value
			unset( $atts['truncate'] );
		}

		$values = array();
		foreach ( $entries as $entry ) {
			$value = self::get_single_field_value( $entry, $field, $atts );
			if ( $value != '' ) {
				$values[] = $value;
			}
		}

		$value = implode( ', ', $values );
		if ( $value == '' ) {
			$value = $atts['default'];
		}

		if ( $truncate ) {
			$more_text = isset( $atts['more_text'] ) ? sanitize_text_field( $atts['more_text'] ) : '...';
			$value     = FrmAppHelper::truncate( $value, $truncate, 3, $more_text );
		}

		return $value;
	}

	private static function get_single_field_value( $entry, $field, $atts ) {
		$value = FrmProEntryMetaHelper::get_post_or_meta_value( $entry, $field, $atts );
		$atts['type']     = $field->type;
		$atts['post_id']  = $entry->post_id;
		$atts['entry_id'] = $entry->id;

		self::add_frm_field_value_atts_for_file_upload_field( $field, $atts );

		$tested_field_types = array( 'time', 'file' );

		if ( in_array( $field->type, $tested_field_types ) || ! empty( $atts['format'] ) || ( isset( $atts['show'] ) && ! empty( $atts['show'] ) ) ) {

			if ( empty( $atts['format'] ) ) {
				unset( $atts['format'] );
			}

			$value = FrmFieldsHelper::get_display_value( $value, $field, $atts );
		} else {
			$value = FrmEntriesHelper::display_value( $value, $field, $atts);
		}

		return $value;
	}

	/**
	 * Add some default attributes for a file upload field in the frm-field-value shortcode
	 *
	 * @since 2.02.11
	 *
	 * @param object $field
	 * @param array $atts
	 */
    private static function add_frm_field_value_atts_for_file_upload_field( $field, &$atts ) {
	    if ( $field->type != 'file' ) {
	    	return;
	    }

	    if ( ! isset( $atts['show_filename'] ) ) {
		    $atts['show_filename'] = false;
	    }

	    if ( ! isset( $atts['size'] ) ) {
		    $atts['size'] = 'thumbnail';
	    }

	    // Show the image by default, for reverse compatibility
	    if ( ! isset( $atts['html'] ) ) {

	    	if ( ! isset( $atts['show_image'] ) ) {
			    $atts['show_image'] = 1;
		    }

		    if ( ! isset( $atts['add_link'] ) ) {
			    $atts['add_link'] = 1;
		    }
	    }
    }

	/**
	 * Get entry object for frm_field_value shortcode
	 * Uses user_id, entry, or ip atts to fetch the entry
	 *
	 * @since 2.0.13
	 * @param object $field
	 * @param array $atts
	 * @return array $entry
	 */
	private static function get_frm_field_value_entry( $field, &$atts ) {
		$query = array( 'form_id' => $field->form_id );
		$order = array( 'order_by' => 'created_at DESC' );

		if ( $atts['user_id'] ) {
			// make sure we are not getting entries for logged-out users
			$query['user_id'] = (int) FrmAppHelper::get_user_id_param( $atts['user_id'] );
			$query['user_id !'] = 0;
		}

		if ( $atts['entry'] ) {
			if ( ! is_numeric($atts['entry']) ) {
				$atts['entry'] = FrmAppHelper::simple_get( $atts['entry'], 'sanitize_title', $atts['entry'] );
			}

			if ( empty( $atts['entry'] ) ) {
				return array();
			}

			if ( is_numeric( $atts['entry'] ) ) {
				$query[] = array( 'or' => 1, 'id' => $atts['entry'], 'parent_item_id' => $atts['entry'] );
			} else {
				$query[] = array( 'item_key' => $atts['entry'] );
			}
		} else {
			// get the latest entry
			$order['limit'] = 1;
		}

		if ( $atts['ip'] ) {
			$use_current = $atts['ip'] === true || $atts['ip'] === '1' || $atts['ip'] === 'current';
			$query['ip'] = $use_current ? FrmAppHelper::get_ip_address() : $atts['ip'];
		}

		$entry = FrmDb::get_results( 'frm_items', $query, 'post_id, id', $order );

		return $entry;
	}

	public static function show_entry_shortcode( $atts ) {
		return FrmEntriesController::show_entry_shortcode( $atts );
	}

	/**
     * Alternate Row Color for Default HTML
	 *
     * @return string
     */
	public static function change_row_color() {
		global $frm_email_col;

        $bg_color = 'bg_color';
		if ( $frm_email_col ) {
		    $bg_color .= '_active';
			$frm_email_col = false;
		} else {
			$frm_email_col = true;
		}

        $bg_color = FrmStylesController::get_style_val($bg_color);
		$alt_color = 'background-color:#' . $bg_color . ';';
		return $alt_color;
	}

	public static function maybe_set_cookie( $entry_id, $form_id ) {
        if ( defined('WP_IMPORTING') || defined('DOING_AJAX') || defined('REST_REQUEST') ) {
            return;
        }

        if ( isset($_POST) && isset($_POST['frm_skip_cookie']) ) {
            self::set_cookie($entry_id, $form_id);
            return;
        }

        include(FrmProAppHelper::plugin_path() . '/classes/views/frmpro-entries/set_cookie.php');
    }

    /* AJAX */

	public static function wp_ajax_destroy() {
        check_ajax_referer( 'frm_ajax', 'nonce' );

        $echo = true;
        if ( isset($_REQUEST['redirect']) ) {
            // don't echo if redirecting
            $echo = false;
        }
        self::ajax_destroy(false, true, $echo);

        if ( ! $echo ) {
            // redirect instead of loading a blank page
            wp_redirect( esc_url_raw( get_permalink( $_REQUEST['redirect'] ) ) );
            die();
        }

        wp_die();
    }

	public static function ajax_destroy( $form_id = false, $ajax = true, $echo = true ) {
        global $wpdb, $frm_vars;

		$entry_key = FrmAppHelper::get_param( 'entry', '', 'get', 'sanitize_title' );
        if ( ! $form_id ) {
			$form_id = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
        }

        if ( ! $entry_key ) {
            return;
        }

        if ( isset( $frm_vars['deleted_entries'] ) && is_array( $frm_vars['deleted_entries'] ) && in_array( $entry_key, $frm_vars['deleted_entries'] ) ) {
            return;
        }

		if ( is_numeric( $entry_key ) ) {
			$where = array( 'id' => $entry_key );
		} else {
			$where = array( 'item_key' => $entry_key );
		}

		$entry = FrmDb::get_row( $wpdb->prefix . 'frm_items', $where, 'id, form_id, is_draft, user_id' );
        unset( $where );

        if ( ! $entry || ( $form_id && $entry->form_id != (int) $form_id ) ) {
            return;
        }

        $message = self::maybe_delete_entry($entry);
        if ( $message && ! is_numeric($message) ) {
            if ( $echo ) {
				echo '<div class="frm_message">' . $message . '</div>';
            }
            return;
        }

        if ( ! isset( $frm_vars['deleted_entries'] ) || empty( $frm_vars['deleted_entries'] ) ) {
            $frm_vars['deleted_entries'] = array();
        }
        $frm_vars['deleted_entries'][] = $entry->id;

        if ( $ajax && $echo ) {
			$message = 'success';
			echo 'success';
        } else if ( ! $ajax ) {
			$message = apply_filters( 'frm_delete_message', esc_html__( 'Your entry was successfully deleted', 'formidable-pro' ), $entry );

            if ( $echo ) {
				echo '<div class="frm_message">' . $message . '</div>';
            }
        } else {
            $message = '';
        }

        return $message;
    }

	public static function maybe_delete_entry( $entry ) {
		FrmEntry::maybe_get_entry( $entry );

        if ( ! $entry || ! FrmProEntriesHelper::user_can_delete($entry) ) {
			return __( 'There was an error deleting that entry', 'formidable-pro' );
        }

		return FrmEntry::destroy( $entry->id );
    }

	public static function send_email() {
        if ( current_user_can('frm_view_forms') || current_user_can('frm_edit_forms') || current_user_can('frm_edit_entries') ) {
            if ( FrmAppHelper::doing_ajax() ) {
                check_ajax_referer( 'frm_ajax', 'nonce' );
            }
			$entry_id = FrmAppHelper::get_param( 'entry_id', '', 'get', 'absint' );
			$form_id = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );

			add_filter( 'frm_echo_emails', '__return_true' );
			ob_start();
			FrmFormActionsController::trigger_actions( 'create', $form_id, $entry_id, 'email' );
			$emails = ob_get_contents();
			ob_end_clean();

			if ( empty( $emails ) ) {
				$emails = __( 'no one', 'formidable-pro' );
			}

			printf( esc_html__( 'Resent to %s', 'formidable-pro' ), esc_html( $emails ) );
			self::suggest_smtp();
		} else {
			esc_html_e( 'Resent to No one! You do not have permission', 'formidable-pro' );
        }
        wp_die();
    }

	/**
	 * Include a link to the SMTP page after an email is resent.
	 *
	 * @since 4.04.04
	 */
	private static function suggest_smtp() {
		$suggest_smtp = class_exists( 'FrmSMTPController' ) && current_user_can( 'activate_plugins' ) && ! function_exists( 'wp_mail_smtp' );
		if ( ! $suggest_smtp ) {
			return;
		}

		$link = admin_url( 'admin.php?page=formidable-smtp' );
		?>
		<p>
			<a href="<?php echo esc_url( $link ); ?>" class="frm_pro_tip">
				<?php FrmAppHelper::icon_by_class( 'frmfont frm_star_full_icon', array( 'aria-hidden' => 'true' ) ); ?>
				<?php esc_html_e( 'Not receiving emails?', 'formidable-pro' ); ?>
				<span class="frm-tip-cta">
					<?php esc_html_e( 'Setup SMTP.', 'formidable-pro' ); ?>
				</span>
			</a>
		</p>
		<?php
	}

	public static function ajax_set_cookie() {
		check_ajax_referer( 'frm_ajax', 'nonce' );
		self::set_cookie();
		wp_die();
	}

	public static function set_cookie( $entry_id = false, $form_id = false ) {
		if ( headers_sent() ) {
			return;
		}

		if ( ! apply_filters('frm_create_cookies', true) ) {
			return;
		}

		if ( ! $entry_id ) {
			$entry_id = FrmAppHelper::get_param( 'entry_id', '', 'get', 'absint' );
		}

		if ( ! $form_id ) {
			$form_id = FrmAppHelper::get_param( 'form_id', '', 'get', 'absint' );
		}

		$form = FrmForm::getOne($form_id);
		if ( ! isset( $form->options['single_entry_type'] ) || $form->options['single_entry_type'] !== 'cookie' ) {
			return;
		}

		$expiration = isset( $form->options['cookie_expiration'] ) ? ( (float) $form->options['cookie_expiration'] * 60 * 60 ) : 30000000;
		$expiration = apply_filters('frm_cookie_expiration', $expiration, $form_id, $entry_id);
		setcookie( 'frm_form' . $form_id . '_' . COOKIEHASH, current_time('mysql', 1), time() + $expiration, COOKIEPATH, COOKIE_DOMAIN, is_ssl() );
	}

	public static function ajax_create() {
		if ( ! FrmAppHelper::doing_ajax() || ! isset( $_POST['form_id'] ) ) {
			// normally, this function would be triggered with the wp_ajax hook, but we need it fired sooner
			return;
		}

		$allowed_actions = array( 'frm_entries_create', 'frm_entries_update' );
		if ( ! in_array( FrmAppHelper::get_post_param( 'action', '', 'sanitize_title' ), $allowed_actions ) ) {
			// allow ajax creating and updating
			return;
		}

		$response = array( 'errors' => array(), 'content' => '', 'pass' => false );

		$form = FrmForm::getOne( FrmAppHelper::get_post_param( 'form_id', 0, 'absint' ) );
		if ( ! $form ) {
			echo json_encode( $response );
			wp_die();
		}

		$is_ajax_on     = FrmProForm::is_ajax_on( $form );
		$no_ajax_fields = $is_ajax_on ? false : array( 'file' );
		$errors         = FrmEntryValidate::validate( wp_unslash( $_POST ), $no_ajax_fields );

		if ( empty( $errors ) ) {
			if ( $is_ajax_on ) {
				global $frm_vars;
				$frm_vars['ajax'] = true;
				$frm_vars['css_loaded'] = true;

				self::maybe_include_exclude_fields( $form->id );

				// don't load scripts if we are going backwards in the form
				$going_backwards = FrmProFormsHelper::going_to_prev( $form->id );

				// save the entry if there is not another page or when saving a draft
				if ( ( ! isset( $_POST[ 'frm_page_order_' . $form->id ] ) && ! $going_backwards ) || FrmProFormsHelper::saving_draft() ) {
					$processed = true;
					FrmEntriesController::process_entry( $errors, true );
				} else {
					self::maybe_autosave_on_page_turn( $errors, $form );
					$response['page'] = FrmProFormsHelper::get_the_page_number( $form->id );
				}

				$get = FrmProFormState::get_from_request( 'get', array() );
				if ( $get ) {
					FrmProAppController::set_get( $get );
				}

				self::maybe_include_exclude_fields( $form->id );
				$title                = FrmProFormState::get_from_request( 'title', false );
				$description          = FrmProFormState::get_from_request( 'description', false );
				$response['content'] .= FrmFormsController::show_form( $form->id, '', $title, $description );

				// trigger the footer scripts if there is a form to show
				if ( $errors || ! isset( $processed ) || ! empty( $frm_vars['forms_loaded'] ) ) {
					ob_start();
					FrmProFormsController::print_ajax_scripts( $going_backwards ? 'none' : '' );
					FrmProFormsController::footer_js();
					$response['content'] .= ob_get_contents();
					ob_end_clean();

					// Mark the end of added footer content
					$response['content'] .= '<span class="frm_end_ajax_' . $form->id . '"></span>';
				}
			}
		} else {
			$obj = array();
			foreach ( $errors as $field => $error ) {
				$field_id         = str_replace( 'field', '', $field );
				$error            = self::maybe_modify_ajax_error( $error, $field_id, $form, $errors );
				$obj[ $field_id ] = $error;
			}
			$response['errors'] = $obj;

			$invalid_msg = FrmFormsHelper::get_invalid_error_message( array( 'form' => $form ) );
			$response['error_message'] = FrmFormsHelper::get_success_message(
				array(
					'message'  => $invalid_msg, 'form' => $form,
					'entry_id' => 0,
					'class'    => FrmFormsHelper::form_error_class(),
				)
			);
		}

		if ( FrmProFieldCaptcha::posting_captcha_data() ) {
			$checked = FrmProFieldCaptcha::checked();
			if ( $checked ) {
				$response['recaptcha'] = $checked;
			}
		}

		echo json_encode( $response );
		wp_die();
	}

	/**
	 * If a field has custom HTML for errors, apply it around the message.
	 *
	 * @since 5.0.03
	 *
	 * @param string   $error
	 * @param string   $field_id
	 * @param stdClass $form the form being submitted (not necessarily the field's form when embedded/repeated).
	 * @param array    $errors all errors that were caught in this form submission, passed into the frm_before_replace_shortcodes filter for reference.
	 * @return string
	 */
	private static function maybe_modify_ajax_error( $error, $field_id, $form, $errors ) {
		if ( ! is_callable( 'FrmFieldsController::pull_custom_error_body_from_custom_html' ) ) {
			// this function only exists since formidable lite 5.0.03
			// if the lite version has not been updated, leave the error unmodified.
			return $error;
		}

		if ( false !== strpos( $field_id, '-' ) ) {
			// repeated fields look like field_id-repeater_id-iteration, so pull the first value for the field id.
			list( $use_field_id ) = explode( '-', $field_id );
		} else {
			$use_field_id = $field_id;
		}

		if ( ! is_numeric( $use_field_id ) ) {
			return $error;
		}

		$use_field = FrmField::getOne( $use_field_id );

		if ( ! $use_field ) {
			return $error;
		}

		$use_field  = FrmFieldsHelper::setup_edit_vars( $use_field );
		$error_body = FrmFieldsController::pull_custom_error_body_from_custom_html( $form, $use_field, $errors );

		if ( false !== $error_body ) {
			$error = str_replace( '[error]', $error, $error_body );
			$error = str_replace( '[key]', $field_id, $error );
		}

		return $error;
	}

	/**
	 * @param int $form_id
	 * @return void
	 */
	public static function maybe_include_exclude_fields( $form_id ) {
		$include_fields = FrmProFormState::get_from_request( 'include_fields', array() );
		if ( $include_fields ) {
			global $frm_vars;
			$frm_vars['show_fields'] = $include_fields;
		}
	}

	public static function setup_edit_vars( $values ) {
        if ( ! isset( $values['edit_value'] ) ) {
			$values['edit_value'] = ( $_POST && isset( $_POST['options']['edit_value'] ) ) ? wp_kses_post( $_POST['options']['edit_value'] ) : __( 'Update', 'formidable-pro' );
        }

        if ( ! isset($values['edit_msg']) ) {
			if ( $_POST && isset( $_POST['options']['edit_msg'] ) ) {
				$values['edit_msg'] = wp_kses_post( $_POST['options']['edit_msg'] );
            } else {
				$frmpro_settings = FrmProAppHelper::get_settings();
                $values['edit_msg'] = $frmpro_settings->edit_msg;
            }
        }

        return $values;
    }

	public static function edit_entry_ajax() {
		$id             = FrmAppHelper::get_param( 'id', '', 'post', 'absint' );
		$entry_id       = FrmAppHelper::get_param( 'entry_id', 0, 'post', 'absint' );
		$post_id        = FrmAppHelper::get_param( 'post_id', 0, 'post', 'sanitize_title' );
		$fields         = FrmAppHelper::get_param( 'fields', array(), 'post', 'sanitize_text_field' );
		$exclude_fields = FrmAppHelper::get_param( 'exclude_fields', array(), 'post', 'sanitize_text_field' );
		$start_page     = FrmAppHelper::get_param( 'start_page', 1, 'post', 'absint' );

		global $frm_vars;
		$frm_vars['footer_loaded'] = true;
		$frm_vars['inplace_edit']  = true;

		if ( $entry_id ) {
			$_GET['entry'] = $entry_id;
		}

		if ( $post_id && is_numeric( $post_id ) ) {
			global $post;
			if ( ! $post ) {
				$post = get_post( $post_id );
			}
		}

		FrmProFormsController::mark_jquery_as_loaded();

		$atts = compact( 'id', 'entry_id', 'fields', 'exclude_fields' );

		if ( 1 !== $start_page ) {
			self::maybe_set_page_from_attribute( $id, $start_page );
		} else {
			self::maybe_set_page( $atts );
		}

		echo FrmFormsController::get_form_shortcode( $atts );

		FrmProFormsController::print_ajax_scripts( 'all' );

		wp_die();
	}

	/**
	 * @param int $form_id
	 * @param int $start_page
	 */
	private static function maybe_set_page_from_attribute( $form_id, $start_page ) {
		$start_page_order = self::get_order_of_start_page_attribute( $form_id, $start_page );
		if ( $start_page_order > 1 ) {
			self::set_page( $form_id, $start_page_order );
		}
	}

	/**
	 * @param int $form_id
	 * @param int $page
	 * @return int
	 */
	private static function get_order_of_start_page_attribute( $form_id, $page ) {
		$page_break_orders = self::get_page_break_orders( $form_id );
		$index             = $page - 2; // offset by 2 because the first page break is not a real field and arrays are 0 indexed.
		return array_key_exists( $index, $page_break_orders ) ? $page_break_orders[ $index ] : 1;
	}

	/**
	 * @param int $form_id
	 * @param int $page_break_order
	 */
	private static function set_page( $form_id, $page_break_order ) {
		$_POST[ 'frm_page_order_' . $form_id ] = $page_break_order;
	}

	/**
	 * @param array $atts including keys id (form id), entry_id, fields, exclude_fields.
	 */
	private static function maybe_set_page( $atts ) {
		$page = self::get_page_from_attributes( $atts );
		if ( 1 !== $page ) {
			self::set_page( $atts['id'], $page );
		}
	}

	/**
	 * @param array $atts including keys id (form id), entry_id, fields, exclude_fields.
	 * @return int the page break field order to start on.
	 */
	private static function get_page_from_attributes( $atts ) {
		$page = 1;

		if ( empty( $atts['id'] ) || ( empty( $atts['fields'] ) && empty( $atts['exclude_fields'] ) ) ) {
			// return the first page if information is missing or all fields are present.
			return $page;
		}

		$form_id           = $atts['id'];
		$page_break_orders = self::get_page_break_orders( $form_id );

		if ( ! $page_break_orders ) {
			// stop if there are no page breaks for this form.
			return $page;
		}

		$first_field_order = self::get_order_of_first_field( $atts );

		foreach ( $page_break_orders as $page_break_order ) {
			if ( $page_break_order > $first_field_order ) {
				break;
			}
			$page = $page_break_order;
		}

		return $page;
	}

	/**
	 * @param int $form_id
	 * @return array<int> field orders for all page break fields.
	 */
	private static function get_page_break_orders( $form_id ) {
		return FrmDb::get_col(
			'frm_fields',
			array(
				'type'    => 'break',
				'form_id' => $form_id,
			),
			'field_order',
			array(
				'order_by' => 'field_order',
			)
		);
	}

	/**
	 * Get the field_order of the first field based off of what is included and excluded with field attributes.
	 *
	 * @param array $atts including keys id (form id), entry_id, fields, exclude_fields.
	 * @return int the lowest field_order value from the set of fields.
	 */
	private static function get_order_of_first_field( $atts ) {
		$includes = ! empty( $atts['fields'] ) ? self::create_id_key_condition_pair( $atts['fields'] ) : array();
		$excludes = ! empty( $atts['exclude_fields'] ) ? self::create_id_key_condition_pair( $atts['exclude_fields'], false ) : array();
		$where    = self::build_where_for_first_field_check( $atts['id'], $includes, $excludes );
		$args     = array( 'order_by' => 'field_order' );
		return FrmDb::get_var( 'frm_fields', $where, 'field_order', $args );
	}

	/**
	 * @param array|string $fields
	 * @param bool         $include
	 * @return array
	 */
	private static function create_id_key_condition_pair( $fields, $include = true ) {
		$fields = self::maybe_explode( $fields );
		$ids    = self::pull_ids( $fields );
		$keys   = self::pull_keys( $fields );
		$pair   = array();
		$suffix = $include ? '' : ' not';

		if ( $ids ) {
			$pair[ 'id' . $suffix ] = $ids;
		}

		if ( $keys ) {
			$pair[ 'field_key' . $suffix ] = $keys;
			if ( $ids ) {
				$pair['or'] = 1;
			}
		}

		return $pair;
	}

	/**
	 * @param int $form_id
	 * @param array $includes
	 * @param array $excludes
	 * @return array
	 */
	private static function build_where_for_first_field_check( $form_id, $includes, $excludes ) {
		$where = array();

		if ( $includes ) {
			$where[] = $includes;
		}

		if ( $excludes ) {
			$where[] = $excludes;
		}

		$where[] = array(
			'form_id' => $form_id,
			'type !'  => 'break',
		);

		return $where;
	}

	/**
	 * @param array|string $ids
	 */
	private static function maybe_explode( $ids ) {
		return is_array( $ids ) ? $ids : explode( ',', $ids );
	}

	/**
	 * @param array $values
	 * @return array<int> ids
	 */
	private static function pull_ids( $values ) {
		return array_filter( $values, 'is_numeric' );
	}

	/**
	 * @param array $values
	 * @return array<string> keys
	 */
	private static function pull_keys( $values ) {
		return array_filter(
			$values,
			function( $value ) {
				return ! is_numeric( $value );
			}
		);
	}

	public static function update_field_ajax() {
		//check_ajax_referer( 'frm_ajax', 'nonce' );

		$entry_id = FrmAppHelper::get_param( 'entry_id', 0, 'post', 'absint' );
		$field_id = FrmAppHelper::get_param( 'field_id', 0, 'post', 'sanitize_title' );
		$value = FrmAppHelper::get_param( 'value', '', 'post', 'wp_kses_post' );
		FrmAppHelper::sanitize_value( 'wp_specialchars_decode', $value );

		FrmField::maybe_get_field( $field_id );
		if ( $field_id && FrmProEntriesHelper::user_can_edit( $entry_id, $field_id->form_id ) ) {
			$updated = FrmProEntryMeta::update_single_field( compact( 'entry_id', 'field_id', 'value' ) );
			echo $updated;
		}

		wp_die();
	}

	public static function redirect_url( $url ) {
		$url = str_replace( array( ' ', '[', ']', '|', '@' ), array( '%20', '%5B', '%5D', '%7C', '%40' ), $url );
		return $url;
	}

	/**
	 * @param stdClass $field
	 * @return bool
	 */
	public static function field_column_is_sortable( $sortable, $field ) {
		if ( ! $sortable && ! empty( $field->field_options['post_field'] ) ) {
			$sortable_options = array( 'post_title', 'post_content', 'post_excerpt', 'post_name', 'post_date', 'post_custom', 'post_status' );
			$sortable         = in_array( $field->field_options['post_field'], $sortable_options, true );
		}
		return $sortable;
	}

	/**
	 * @param string $sort
	 * @param int    $field_id
	 * @param array  $field_options
	 * @return string
	 */
	public static function handle_field_column_sort( $sort, $field_id, $field_options ) {
		if ( '' !== $sort || empty( $field_options['post_field'] ) ) {
			return $sort;
		}

		global $wpdb;

		if ( 'post_custom' === $field_options['post_field'] ) {
			if ( empty( $field_options['custom_field'] ) ) {
				return '';
			}

			$meta_key = sanitize_key( $field_options['custom_field'] );
			return ', (SELECT m.meta_value FROM ' . $wpdb->prefix . 'postmeta m INNER JOIN ' . $wpdb->prefix . 'frm_items i ON i.post_id=m.post_id WHERE m.meta_key = "' . esc_sql( $meta_key ) . '" AND i.id = it.id) as meta_' . $field_id;
		}

		$column = sanitize_key( $field_options['post_field'] );
		return ', (SELECT p.' . $column . ' FROM ' . $wpdb->prefix . 'posts p INNER JOIN ' . $wpdb->prefix . 'frm_items i ON i.post_id=p.ID WHERE i.id = it.id) as meta_' . $field_id;
	}

	/**
	 * AJAX handler for deleting draft entry.
	 *
	 * @since 5.4
	 */
	public static function delete_draft_entry_ajax() {
		check_ajax_referer( 'frm_ajax' );

		$form_id = FrmAppHelper::get_post_param( 'form', 0, 'intval' );
		if ( ! $form_id ) {
			wp_send_json_error();
		}

		$user_id = get_current_user_id();

		global $wpdb;

		$wpdb->delete(
			$wpdb->prefix . 'frm_items',
			array(
				'is_draft' => 1,
				'form_id'  => $form_id,
				'user_id'  => $user_id,
			),
			array( '%d', '%d', '%d' )
		);

		wp_send_json_success();
	}

	/**
	 * @since 3.0
	 * @deprecated 4.0
	 */
	public static function add_edit_link( $entry = array() ) {
		_deprecated_function( __METHOD__, '4.0' );
		FrmProEntriesHelper::edit_button( $entry );
	}

	/**
	 * @deprecated 4.0
	 */
	public static function add_sidebar_links( $entry ) {
		_deprecated_function( __METHOD__, '4.0' );
	}

	/**
	 * @codeCoverageIgnore
	 */
	public static function admin_js() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::admin_js' );
		FrmProFormsController::admin_js();
	}

	/**
	 * @codeCoverageIgnore
	 */
	public static function add_js() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::add_js' );
		FrmProFormsController::add_js();
	}

	/**
	 * @codeCoverageIgnore
	 */
	public static function print_ajax_scripts( $keep = '' ) {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::print_ajax_scripts' );
		FrmProFormsController::print_ajax_scripts();
	}

	/**
	 * @codeCoverageIgnore
	 */
    public static function after_footer_loaded() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::after_footer_loaded' );
		FrmProFormsController::after_footer_loaded();
    }

	/**
	 * @codeCoverageIgnore
	 */
	public static function enqueue_footer_js() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::enqueue_footer_js' );
		FrmProFormsController::enqueue_footer_js();
    }

	/**
	 * @codeCoverageIgnore
	 */
	public static function footer_js() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProFormsController::footer_js' );
		FrmProFormsController::footer_js();
    }

	/**
	 * @codeCoverageIgnore
	 */
	public static function add_duplicate_link( $entry ) {
		_deprecated_function( __METHOD__, '3.0' );
		FrmProEntriesHelper::show_duplicate_link( $entry );
	}

	/**
	 * @codeCoverageIgnore
	 */
	public static function register_scripts() {
		_deprecated_function( __METHOD__, '3.0', 'FrmProAppController::register_scripts' );
		FrmProAppController::register_scripts();
	}

	/**
	 * @deprecated 2.04
	 * @codeCoverageIgnore
	 */
	public static function filter_value_in_single_entry_table( $value, $meta, $entry, $atts = array() ) {
		_deprecated_function( __FUNCTION__, '2.04', 'FrmProEntriesController::get_option_label_for_saved_value');

		if ( isset( $atts['field'] ) ) {
			$field = $atts['field'];
		} else {
			$field = FrmField::getOne( $meta->field_id );
		}
		if ( ! $field ) {
			return $value;
		}

		return self::get_option_label_for_saved_value( $value, $field, $atts );
	}

	/**
	 * @deprecated 4.09
	 */
	public static function register_widgets() {
		return FrmProDisplaysController::deprecated_function( __METHOD__, 'FrmViewsDisplaysController::register_widgets' );
    }
}