Form()
Description #
The form class.
Source #
File: lib/class-form.php
class Form {
/**
* The form name.
*
* @var string
*/
public $form_name = '';
/**
* The form args.
*
* @var array
*/
public $args = array();
/**
* The fields.
*
* @var array
*/
public $fields = array();
/**
* Is form prepared.
*
* @var boolean
*/
public $prepared = false;
/**
* The errors.
*
* @var array
*/
public $errors = array();
/**
* The values.
*
* @var null|array
*/
public $values = null;
/**
* Is editing.
*
* @var boolean
*/
public $editing = false;
/**
* Editing post ID.
*
* @var boolean|integer
*/
public $editing_id = false;
/**
* Is form submitted.
*
* @var bool
*/
public $submitted = false;
/**
* After form HTML.
*
* @var string
*/
public $after_form = '';
/**
* Initialize the class.
*
* @param string $form_name Name of form.
* @param array $args Arguments for form.
*/
public function __construct( $form_name, $args ) {
$this->form_name = $form_name;
$this->args = wp_parse_args(
$args,
array(
'form_tag' => true,
'submit_button' => true,
'submit_label' => __( 'Submit', 'anspress-question-answer' ),
'editing' => false,
'editing_id' => 0,
)
);
$this->editing = $this->args['editing'];
$this->editing_id = $this->args['editing_id'];
}
/**
* Prepare input field.
*
* @return AnsPress\Form
* @since 4.1.0
* @since 4.1.5 Return current instance.
*/
public function prepare() {
if ( empty( $this->args['fields'] ) ) {
return $this;
}
$fields = ap_sort_array_by_order( $this->args['fields'] );
if ( ! ap_opt( 'allow_private_posts' ) && isset( $fields['is_private'] ) ) {
unset( $fields['is_private'] );
}
foreach ( $fields as $field_name => $field_args ) {
if ( empty( $field_args['type'] ) ) {
$field_args['type'] = 'input';
}
$type_class = ucfirst( trim( $field_args['type'] ) );
$field_class = 'AnsPress\\Form\\Field\\' . $type_class;
if ( class_exists( $field_class ) ) {
/**
* Allows filtering field argument before its being passed to Field class.
*
* @param array $field_args Field arguments.
* @param object $form Form class, passed by reference.
* @since 4.1.0
*/
$field_args = apply_filters_ref_array( 'ap_before_prepare_field', array( $field_args, $this ) );
$this->fields[ $field_name ] = new $field_class( $this->form_name, $field_name, $field_args, $this );
}
}
$this->prepared = true;
$this->sanitize_validate();
return $this;
}
/**
* Generate fields HTML markup.
*
* @return string
*/
public function generate_fields() {
$html = '';
if ( false === $this->prepared ) {
$this->prepare();
}
if ( ! empty( $this->fields ) ) {
foreach ( (array) $this->fields as $field ) {
$html .= $field->output();
}
}
return $html;
}
/**
* Generate form.
*
* @param array $form_args {
* Form generate arguments.
*
* @type string $form_action Custom form action url.
* @type array $hidden_fields Custom hidden input fields.
* }
* @return void
* @since 4.1.0
* @since 4.1.8 Inherit `hidden_fields` from form args.
*/
public function generate( $form_args = array() ) {
// Don't do anything if no fields.
if ( empty( $this->args['fields'] ) ) {
echo '<p class="ap-form-nofields">';
echo esc_attr(
sprintf(
// Translators: Placeholder contain form name.
esc_attr__( 'No fields found for form: %s', 'anspress-question-answer' ),
$this->form_name
)
);
echo '</p>';
return;
}
$form_args = wp_parse_args(
$form_args,
array(
'form_action' => '',
'hidden_fields' => false,
'ajax_submit' => true,
'submit_button' => $this->args['submit_button'],
'form_tag' => $this->args['form_tag'],
)
);
if ( ! empty( $this->args['hidden_fields'] ) ) {
$form_args['hidden_fields'] = wp_parse_args( $form_args['hidden_fields'], $this->args['hidden_fields'] );
}
/**
* Allows filtering arguments passed to @see AnsPress\Form\generate() method. Passed
* by reference.
*
* @param array $form_args Form arguments.
* @param object $form Current form object.
* @since 4.1.0
*/
$form_args = apply_filters_ref_array( 'ap_generate_form_args', array( $form_args, $this ) );
$action = ! empty( $form_args['form_action'] ) ? esc_url( $form_args['form_action'] ) : '';
if ( true === $form_args['form_tag'] ) {
echo '<form id="' . esc_attr( $this->form_name ) . '" name="' . esc_attr( $this->form_name ) . '" method="POST" enctype="multipart/form-data" action="' . esc_attr( $action ) . '" ' . ( true === $form_args['ajax_submit'] ? ' apform' : '' ) . '>';
}
// Output form errors.
if ( $this->have_errors() ) {
echo '<div class="ap-form-errors">';
foreach ( (array) $this->errors as $code => $msg ) {
echo '<span class="ap-form-error ecode-' . esc_attr( $code ) . '">' . esc_html( $msg ) . '</span>';
}
echo '</div>';
}
echo $this->generate_fields(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '<input type="hidden" name="ap_form_name" value="' . esc_attr( $this->form_name ) . '" />';
if ( true === $form_args['submit_button'] ) {
echo '<button type="submit" class="ap-btn ap-btn-submit">' . esc_html( $this->args['submit_label'] ) . '</button>';
}
echo '<input type="hidden" name="' . esc_attr( $this->form_name ) . '_nonce" value="' . esc_attr( wp_create_nonce( $this->form_name ) ) . '" />';
echo '<input type="hidden" name="' . esc_attr( $this->form_name ) . '_submit" value="true" />';
// Add custom hidden fields.
if ( ! empty( $form_args['hidden_fields'] ) ) {
foreach ( $form_args['hidden_fields'] as $field ) {
echo '<input type="hidden" name="' . esc_attr( $field['name'] ) . '" value="' . esc_attr( $field['value'] ) . '" />';
}
}
/**
* Action triggered after all form fields are generated and before closing
* form tag. This action can be used to append more fields or HTML in form.
*
* @param object $form Current form class.
*/
do_action_ref_array( 'ap_after_form_field', array( $this ) );
if ( true === $this->args['form_tag'] ) {
echo '</form>';
}
if ( ! empty( $this->after_form ) ) {
echo $this->after_form; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
/**
* Check if current form is submitted.
*
* @return boolean
*/
public function is_submitted() {
$nonce = ap_isset_post_value( esc_attr( $this->form_name ) . '_nonce' );
if ( ap_isset_post_value( esc_attr( $this->form_name ) . '_submit' ) &&
wp_verify_nonce( $nonce, $this->form_name ) ) {
$this->submitted = true;
return true;
}
return false;
}
/**
* Find a field object.
*
* @param string $value Value for argument `$key`.
* @param boolean|array $fields List of field where to search.
* @param string $key Search field by which property of a field object.
* @return object|boolean
*/
public function find( $value, $fields = false, $key = 'original_name' ) {
if ( false === $this->prepared ) {
$this->prepare();
}
$fields = false === $fields ? $this->fields : $fields;
$found = wp_filter_object_list( $fields, array( $key => $value ) );
if ( empty( $found ) ) {
foreach ( $fields as $field ) {
if ( ! empty( $field->child ) && ! empty( $field->child->fields ) ) {
$child_found = $this->find( $value, $field->child->fields );
if ( ! empty( $child_found ) ) {
$found = $child_found;
break;
}
}
}
}
return is_array( $found ) ? reset( $found ) : $found;
}
/**
* Add an error to form object.
*
* @param string $code Error code.
* @param string $msg Error message.
* @return void
*/
public function add_error( $code, $msg = '' ) {
$this->errors[ $code ] = $msg;
}
/**
* Check if form have any error.
*
* @return boolean
*/
public function have_errors() {
return ! empty( $this->errors ) && is_array( $this->errors );
}
/**
* Get a value from a path or default value if the path doesn't exist
*
* @param string $key Path.
* @param mixed $default_value Default value.
* @param array $arr Array to search.
* @return mixed
*/
public function get( $key, $default_value = null, $arr = null ) {
$keys = explode( '.', (string) $key );
if ( null === $arr ) {
$arr = &$this->args;
}
foreach ( $keys as $key ) {
if ( ! array_key_exists( $key, $arr ) ) {
return $default_value;
}
$arr = &$arr[ $key ];
}
return $arr;
}
/**
* Add new field in form.
*
* @param string $path Path of new array item. This must include field name at last.
* @param mixed $val Value to set.
*
* @return void.
*/
public function add_field( $path, $val ) {
$path = is_string( $path ) ? explode( '.', $path ) : $path;
$loc = &$this->args['fields'];
foreach ( (array) $path as $step ) {
$loc = &$loc[ $step ]['fields'];
}
$loc['fields'] = $val;
}
/**
* Validate and sanitize all fields.
*
* @param boolean|array $fields Fields to process.
* @return void
*/
private function sanitize_validate( $fields = false ) {
if ( ! ap_isset_post_value( $this->form_name . '_submit' ) ) {
return;
}
if ( false === $this->prepared ) {
$this->prepare();
}
if ( false === $fields ) {
$fields = $this->fields;
}
foreach ( (array) $fields as $field ) {
if ( ! empty( $field->child ) && ! empty( $field->child->fields ) ) {
$this->sanitize_validate( $field->child->fields );
}
$field->sanitize();
$field->validate();
if ( true === $field->have_errors() ) {
$this->add_error( 'fields-error', __( 'Error found in fields, please check and re-submit', 'anspress-question-answer' ) );
}
}
}
/**
* Get errors of all fields.
*
* @param false|array $fields Fields.
* @return array
*/
public function get_fields_errors( $fields = false ) {
$errors = array();
if ( false === $this->prepared ) {
$this->prepare();
}
if ( false === $fields ) {
$fields = $this->fields;
}
foreach ( (array) $fields as $field ) {
if ( $field->have_errors() ) {
$errors[ $field->id() ] = array( 'error' => $field->errors );
}
if ( ! empty( $field->child ) && ! empty( $field->child->fields ) ) {
$child_errors = $this->get_fields_errors( $field->child->fields );
if ( ! empty( $child_errors ) ) {
$errors[ $field->id() ]['child'] = $child_errors;
}
}
}
return $errors;
}
/**
* Get values from all fields.
*
* @param boolean|array $fields Child fields.
* @return array
* @since 4.1.0
*/
private function field_values( $fields = false ) {
$values = array();
if ( false === $this->prepared ) {
$this->prepare();
}
if ( false === $fields ) {
$fields = $this->fields;
}
foreach ( (array) $fields as $field ) {
$field->pre_get();
$values[ $field->original_name ] = array( 'value' => $field->value() );
if ( ! empty( $field->child ) && ! empty( $field->child->fields ) ) {
$values[ $field->original_name ]['child'] = $this->field_values( $field->child->fields );
}
}
return $values;
}
/**
* Get all values of fields.
*
* @return array|false
* @since 4.1.0
* @since 4.1.5 Return values even if there are errors.
*/
public function get_values() {
if ( ! is_null( $this->values ) ) {
return $this->values;
}
$this->values = $this->field_values();
return $this->values;
}
/**
* Run all after save methods in fields and child fields.
*
* @param boolean|array $fields Fields.
* @param array $args Arguments to be passed to method.
* @return void
* @since 4.1.0
* @since 4.1.5 Delete AnsPress session data.
*/
public function after_save( $fields = false, $args = array() ) {
// Delete session data.
$this->delete_values_session();
if ( false === $this->prepared ) {
$this->prepare();
}
if ( false === $fields ) {
$fields = $this->fields;
}
foreach ( (array) $fields as $field ) {
$field->after_save( $args );
if ( ! empty( $field->child ) && ! empty( $field->child->fields ) ) {
$this->after_save( $field->child->fields, $args );
}
}
}
/**
* Set values for a field.
*
* This must be called before initialization of form.
*
* @param array $values Values.
* @return AnsPress\Form
*
* @since 4.1.0
* @since 4.1.5 Set values after form is prepared. Return current object.
*/
public function set_values( $values ) {
if ( false === $this->prepared ) {
$this->prepare();
}
if ( empty( $values ) ) {
return $this;
}
foreach ( $values as $key => $val ) {
if ( is_array( $val ) && isset( $val['value'] ) ) {
$val = $val['value'];
}
$field = $this->find( $key );
if ( $field ) {
$field->value = $val;
}
}
return $this;
}
/**
* Save current values to AnsPress session so that users unfinished question can
* be retrieved later.
*
* @param integer $id Numerical id.
* @return void
* @since 4.1.5
*/
public function save_values_session( $id = '' ) {
$values = $this->get_values();
if ( ! empty( $values ) ) {
$id = empty( $id ) ? '' : '_' . $id;
anspress()->session->set( $this->form_name . $id, $values );
}
}
/**
* Delete all form data stored in user session.
*
* @param integer $id Numerical id.
* @return void
*/
public function delete_values_session( $id = '' ) {
$id = empty( $id ) ? '' : '_' . $id;
anspress()->session->delete( $this->form_name . $id );
}
}
Expand full source code Collapse full source code View on GitHub: lib/class-form.php:24
Add your comment