AnsPress_Form()

Description #

AnsPress HTML form handler

Source #

File: includes/class/form.php

class AnsPress_Form {

	/**
	 * Name of the form.
	 *
	 * @var string
	 */
	private $name;

	/**
	 * Form arguments.
	 *
	 * @var array
	 */
	private $args = array();

	/**
	 * HTML output.
	 *
	 * @var string
	 */
	private $output = '';

	/**
	 * Current field.
	 *
	 * @var array
	 */
	private $field;

	/**
	 * Form error.
	 *
	 * @var array
	 */
	private $errors;

	/**
	 * Initiate the class.
	 *
	 * @param array $args Form arguments.
	 */
	public function __construct( $args = array() ) {

		// Default form arguments.
		$defaults = array(
			'method'            => 'POST',
			'action'            => '',
			'is_ajaxified'      => false,
			'class'             => 'ap-form',
			'multipart'         => false,
			'submit_button'     => __( 'Submit', 'anspress-question-answer' ),
		);

		// Merge defaults args.
		$this->args = wp_parse_args( $args, $defaults );

		// Set the name of the form.
		$this->name = $this->args['name'];

		global $ap_errors;
		$this->errors = $ap_errors;

		$this->add_default_in_field();

		$this->order_fields();
	}

	/**
	 * Add fields default values.
	 */
	private function add_default_in_field() {
		if ( ! isset( $this->args['fields'] ) ) {
			return;
		}

		foreach ( (array) $this->args['fields'] as $k => $field ) {
			if ( ! is_array( $field ) ) {
				return;
			}

			$this->args['fields'][ $k ] = wp_parse_args( $field, array(
				'order'         => 10,
				'show_desc_tip' => false,
				'type'          => 'text',
			) );

			// Get value from opttions if options_form.
			if ( 'options_form' == $this->name && isset( $field['name'] ) && ! isset( $field['value'] ) ) {
				$this->args['fields'][ $k ]['value'] = ap_opt( $field['name'] );
			}
		}
	}

	/**
	 * Order fields.
	 *
	 * @since 2.0.1
	 */
	private function order_fields() {
		if ( ! isset( $this->args['fields'] ) ) {
			return;
		}

		$this->args['fields'] = ap_sort_array_by_order( $this->args['fields'] );
	}

	/**
	 * Build the form.
	 *
	 * @since 2.0.1
	 */
	public function build() {

		$this->form_head();
		$this->form_fields();

		if ( ! isset( $this->args['hide_footer'] ) || false !== $this->args['hide_footer'] ) {
			$this->hidden_fields();
			$this->form_footer();
		}
	}

	/**
	 * FORM element.
	 *
	 * @since 2.0.1
	 */
	private function form_head() {

		$attr = '';

		if ( ! empty( $this->args['attr'] ) ) {
			$attr .= $this->args['attr'];
		}

		if ( $this->args['is_ajaxified'] ) {
			$attr .= ' data-action="ap_ajax_form"';
		}

		if ( ! empty( $this->args['class'] ) ) {
			$attr .= ' class="' . $this->args['class'] . '"';
		}

		ob_start();

		/**
		 * ACTION: ap_form_before_[form_name]
		 * action for hooking before form.
		 *
		 * @since 2.0.1
		 */
		do_action( 'ap_form_before_' . $this->name );

		$this->output .= ob_get_clean();

		// Add enctype if form is multipart.
		$multipart = $this->args['multipart'] ? ' enctype="multipart/form-data"' : '';
		if ( ! isset( $this->args['hide_footer'] ) || false !== $this->args['hide_footer'] ) {
			$this->output .= '<form name="' . $this->args['name'] . '" id="' . $this->args['name'] . '" method="' . $this->args['method'] . '" action="' . $this->args['action'] . '"' . $attr . $multipart . '>';
		}
	}

	/**
	 * FORM footer.
	 *
	 * @since 2.0.1
	 */
	private function form_footer() {

		ob_start();

		/**
		 * ACTION: ap_form_bottom_[form_name]
		 * action for hooking captcha and extar fields
		 *
		 * @since 2.0.1
		 */
		do_action( 'ap_form_bottom_' . $this->name );
		$this->output .= ob_get_clean();

		$this->output .= '<button type="submit" class="ap-btn ap-btn-submit">' . $this->args['submit_button'] . '</button>';

		if ( isset( $this->args['show_reset'] ) && true === $this->args['show_reset'] ) {
			$this->output .= '<input type="submit" name="reset" class="button ap-btn ap-btn-reset" value="' . __( 'Reset', 'anspress-question-answer' ) . '" />';
		}

		if ( isset( $this->args['show_cancel'] ) && true === $this->args['show_cancel'] ) {
			$this->output .= '<button type="button" class="ap-btn ap-btn-cancel">' . __( 'Cancel', 'anspress-question-answer' ) . '</button>';
		}

		$this->output .= '</form>';
	}

	/**
	 * Add nonce field
	 */
	private function nonce() {
		$nonce_name = isset( $this->args['nonce_name'] ) ? $this->args['nonce_name'] : $this->name;
		$this->output .= wp_nonce_field( $nonce_name, '__nonce', true, false );
	}

	/**
	 * Form hidden fields.
	 *
	 * @since 2.0.1
	 */
	private function hidden_fields() {
		$this->output .= '<input type="hidden" name="ap_form_action" value="' . $this->name . '">';
		$this->nonce();
	}

	/**
	 * Form field label.
	 *
	 * @since 2.0.1
	 */
	private function label() {

		if ( $this->field['label'] && ! $this->field['show_desc_tip'] ) {
			$this->output .= '<label class="ap-form-label" for="'. @$this->field['name'] .'">'. @$this->field['label'].'</label>';
		} elseif ( $this->field['label'] ) {
			$this->output .= '<label class="ap-form-label" for="'. @$this->field['name'] .'">'. @$this->field['label'];
			$this->desc();
			$this->output .= '</label>';
		}
	}

	/**
	 * Output placeholder attribute of current field.
	 *
	 * @return string
	 * @since 2.0.1
	 */
	private function placeholder() {
		return ! empty( $this->field['placeholder'] ) ? ' placeholder="' . $this->field['placeholder'] . '"' : '';
	}

	/**
	 * Output description of a form fields.
	 *
	 * @since 2.0.1
	 */
	private function desc() {
		if ( ! $this->field['show_desc_tip'] ) {
			$this->output .= ( ! empty( $this->field['desc'] ) ? '<p class="ap-field-desc">' . $this->field['desc'] . '</p>' : '');
		} else {

			$this->output .= ( ! empty( $this->field['desc'] ) ? '<span class="ap-tip ap-field-desc" data-tipposition="right" title="' . esc_html( $this->field['desc'] ) . '">?</span>' : '');
		}
	}

	/**
	 * Output text fields.
	 *
	 * @param array  $field Field.
	 * @param string $type Type of field.
	 * @since 2.0
	 */
	private function text_field( $field = array(), $type = 'text' ) {

		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		$placeholder = $this->placeholder();
		$autocomplete = isset( $field['autocomplete'] )  ? ' autocomplete="off"' : '';

		$this->output .= '<div class="ap-form-fields-in">';

		if ( ! isset( $field['repeatable'] ) || ! $field['repeatable'] ) {

			$this->output .= '<input id="' . $field['name'] . '" type="' . $type . '" class="ap-form-control" value="' . $field['value'] . '" name="' . $field['name'] . '"' . $placeholder . ' ' . $this->attr( $field ) . $autocomplete . ' />';

			if ( 'password' === $type ) {
				$this->output .= '<input id="' . $field['name'] . '-1" type="' . $type . '" class="ap-form-control" value="' . $field['value'] . '" name="' . $field['name'] . '-1" placeholder="' . __( 'Repeat your password', 'anspress-question-answer' ).'" ' . $this->attr( $field ) . $autocomplete . ' />';
			}
		} else {
			if ( ! empty( $field['value'] ) && is_array( $field['value'] ) ) {
				$this->output .= '<div id="ap-repeat-c-' . $field['name'] . '" class="ap-repeatbable-field">';

				foreach ( $field['value'] as $k => $rep_f ) {
					$this->output .= '<div id="ap_text_rep_' . $field['name'] . '_' . $k . '" class="ap-repeatbable-field"><input id="' . $field['name'] . '_' . $k . '" type="text" class="ap-form-control ap-repeatable-text" value="' . $rep_f . '" name="' . $field['name'] . '[' . $k . ']"' . $placeholder . ' ' . $this->attr( $field ) . $autocomplete . ' />';
					$this->output .= '<button data-action="ap_delete_field" type="button" data-toggle="'. $field['name'] . '_' . $k . '">' . __( 'Delete', 'anspress-question-answer' ) . '</button>';
					$this->output .= '</div>';
				}

				$this->output .= '</div>';

				$this->output .= '<div id="ap-repeatbable-field-' . $field['name'] . '" class="ap-reapt-field-copy">';
				$this->output .= '<div id="ap_text_rep_' . $field['name'] . '_#" class="ap-repeatbable-field"><input id="' . $field['name'] . '_#" type="text" class="ap-form-control ap-repeatable-text" value="" name="' . $field['name'] . '[#]"' . $placeholder . ' ' . $this->attr( $field ) . $autocomplete . ' />';
				$this->output .= '<button data-action="ap_delete_field" type="button" data-toggle="' . $field['name'] . '_#">' . __( 'Delete', 'anspress-question-answer' ) . '</button>';
				$this->output .= '</div></div>';
				$this->output .= '<button data-action="ap_add_field" type="button" data-field="ap-repeat-c-' . $field['name'] . '" data-copy="ap-repeatbable-field-' . $field['name'] . '">' . __( 'Add more', 'anspress-question-answer' ) . '</button>';
			}
		}

		$this->error_messages();

		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc();
		}

		$this->output .= '</div>';
	}

	/**
	 * Output text type="number".
	 *
	 * @param       array $field
	 * @return      void
	 * @since       2.0.0
	 */
	private function number_field( $field = array() ) {

		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		$placeholder = $this->placeholder();
		$autocomplete = isset( $field['autocomplete'] )  ? ' autocomplete="off"' : '';
		$this->output .= '<div class="ap-form-fields-in">';
		$this->output .= '<input id="'. @$field['name'] .'" type="number" class="ap-form-control" value="'. @$field['value'] .'" name="'. @$field['name'] .'"'.$placeholder.' '. $this->attr( $field ) .$autocomplete.' />';
		$this->error_messages();

		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc();
		}

		$this->output .= '</div>';
	}

	/**
	 * Checkbox field.
	 *
	 * @param  array $field Field.
	 * @since 2.0.1
	 */
	private function checkbox_field( $field = array() ) {
		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		$this->output .= '<div class="ap-form-fields-in">';

		if ( ! empty( $field['desc'] ) ) {
			$this->output .= '<label for="' . $field['name'] . '">';
		}

		$this->output .= '<input id="' . $field['name'] . '" type="checkbox" class="ap-form-control" value="1" name="' . $field['name'] . '" ' . checked( (bool) $field['value'], true, false ) . ' ' . $this->attr( $field ) . ' />';

		// Hack for getting value of unchecked checkbox.
		$this->output .= '<input type="hidden" value="0" name="_hidden_' . $field['name'] . '" />';

		if ( ! empty( $field['desc'] ) ) {
			$this->output .= $field['desc'] . '</label>';
		}

		$this->error_messages();

		$this->output .= '</div>';
	}

	/**
	 * Radio field.
	 *
	 * @param  array $field Field.
	 * @since 2.0.1
	 */
	private function radio_field( $field = [] ) {
		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		$this->output .= '<div class="ap-form-fields-in">';

		foreach ( (array) $field['options'] as $opt_value => $opt_label ) {

			$this->output .= '<label>';
			$this->output .= '<input id="' . $field['name'] . '" type="radio" class="ap-form-control" value="' . esc_attr( $opt_value ) . '" name="' . $field['name'] . '" ' . checked( $opt_value, $field['value'], false ) . ' ' . $this->attr( $field ) . ' />';

			$this->output .= $opt_label;
			$this->output .=  '</label>';
		}

		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc();
		}

		$this->error_messages();
		$this->output .= '</div>';
	}

	/**
	 * Output select field options.
	 *
	 * @param  array $field Field.
	 * @return void
	 * @since 2.0.1
	 */
	private function select_options( $field = array() ) {

		foreach ( $field['options'] as $k => $opt ) {
			$this->output .= '<option value="'.$k.'" '.selected( $k, $field['value'], false ).'>'.$opt.'</option>'; }
	}

	/**
	 * Select fields
	 * @param  array $field
	 * @return void
	 * @since 2.0.1
	 */
	private function select_field($field = array()) {

		if ( isset( $field['label'] ) ) {
			$this->label(); }
		$this->output .= '<div class="ap-form-fields-in">';
		$this->output .= '<select id="'. @$field['name'] .'" class="ap-form-control" value="'. @$field['value'] .'" name="'. @$field['name'] .'" '. $this->attr( $field ) .'>';
		$this->output .= '<option value=""></option>';
		$this->select_options( $field );
		$this->output .= '</select>';
		$this->error_messages();
		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc(); }
		$this->output .= '</div>';
	}

	/**
	 * Taxonomy select field
	 * @param  array $field
	 * @return void
	 * @since 2.0.1
	 */
	private function taxonomy_select_field($field = array()) {

		if ( isset( $field['label'] ) ) {
			$this->label(); }
		$this->output .= '<div class="ap-form-fields-in">';

		$taxonomies = wp_dropdown_categories( array( 'taxonomy' => $field['taxonomy'], 'orderby' => @$field['orderby'], 'hide_empty' => 0, 'hierarchical' => 1, 'selected' => @$field['value'], 'name' => @$field['name'], 'class' => 'ap-form-control', 'id' => @$field['name'], 'echo' => false ) );
		$this->output .= $taxonomies;

		$this->error_messages();
		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc(); }
		$this->output .= '</div>';
	}

	/**
	 * Page select field
	 * @param  array $field
	 * @return void
	 * @since 2.0.0
	 */
	private function page_select_field($field = array()) {

		if ( isset( $field['label'] ) ) {
			$this->label(); }
		$this->output .= '<div class="ap-form-fields-in">';
		$this->output .= wp_dropdown_pages( array( 'show_option_none' => __( 'Select a page', 'anspress-question-answer' ), 'selected' => @$field['value'], 'name' => @$field['name'], 'post_type' => 'page', 'echo' => false ) );
		$this->error_messages();
		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc(); }
		$this->output .= '</div>';
	}

	/**
	 * Textarea field output.
	 * @param       array $field Field args.
	 * @return      void
	 * @since       2.0
	 */
	private function textarea_field($field = array()) {
		$field = wp_parse_args( $field, array(
			'name' => 'textarea',
			'rows' => '6',
			'value' => '',
		) );

		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		$this->output .= '<div class="ap-form-fields-in">';
		$placeholder = $this->placeholder();

		$this->output .= '<textarea id="'. $field['name'] .'" rows="'. $field['rows'] .'" class="ap-form-control" name="'. $field['name'] .'"'.$placeholder.' '. $this->attr( $field ) .'>'. $field['value'] .'</textarea>';

		$this->error_messages();

		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc();
		}

		$this->output .= '</div>';
	}

	/**
	 * Create wp_editor field
	 * @param  array $field
	 * @return void
	 * @since 2.0.1
	 */
	private function editor_field($field = array()) {
		if ( isset( $field['label'] ) ) {
			$this->label();
		}

		if ( $field['settings']['tinymce'] !== false ) {
			$field['settings']['tinymce'] = array(
				'content_css' => ap_get_theme_url( 'css/editor.css' ),
				'wp_autoresize_on' => true,
			);
		}

		/**
		 * FILTER: ap_pre_editor_settings
		 * Can be used to mody wp_editor settings
		 * @var array
		 * @since 2.0.1
		 */

		$settings = apply_filters( 'ap_pre_editor_settings', $field['settings'] );

		$this->output .= '<div class="ap-form-fields-in">';
		// Turn on the output buffer
		ob_start();
		echo '<div class="ap-editor">';
		wp_editor( $field['value'], $field['name'], $settings );
		echo '</div>';
		$this->output .= ob_get_clean();
		$this->error_messages();
		if ( ! $this->field['show_desc_tip'] ) {
			$this->desc();
		}
		$this->output .= '</div>';
	}
	/**
	 * For creating hidden input fields
	 * @param  array $field
	 * @return void
	 * @since 2.0.1
	 */
	private function hidden_field( $field = array() ) {
		$this->output .= '<input type="hidden" value="'. @$field['value'] .'" name="'. @$field['name'] .'" '. $this->attr( $field ) .' />';
	}

	private function custom_field($field = array()) {
		$this->output .= $field['html'];
	}

	private function attr( $field ) {
		return isset( $field['attr'] ) ? $field['attr'] : '';
	}

	/**
	 * Check if current field have any error
	 * @return boolean
	 * @since 2.0.1
	 */
	private function have_error() {
		if ( isset( $this->field['name'] ) && isset( $this->errors[$this->field['name']] ) ) {
			return true;
		}

		return false;
	}

	private function error_messages() {
		if ( isset( $this->errors[$this->field['name']] ) ) {
			$this->output .= '<div class="ap-form-error-messages">';

			foreach ( $this->errors[$this->field['name']] as $error ) {
				$this->output .= '<p class="ap-form-error-message">'. $error .'</p>';
			}

			$this->output .= '</div>';
		}
	}

	/**
	 * Out put all form fields based on on their type
	 * @return void
	 * @since  2.0
	 */
	private function form_fields() {
		/**
		 * FILTER: ap_pre_form_fields
		 * Provide filter to add or override form fields before output.
		 * @var array
		 * @since 2.0.1
		 */
		$this->args['fields'] = apply_filters( 'ap_pre_form_fields', $this->args['fields'] );

		foreach ( $this->args['fields'] as $field ) {

			$this->field = $field;

			$error_class = $this->have_error() ? ' ap-have-error' : '';

			if ( isset( $this->args['field_hidden'] ) && $this->args['field_hidden'] ) {
				if ( isset( $field['name'] ) && $field['type'] != 'hidden' && (@$field['visibility'] != 'me' || ( @$field['visibility'] == 'me' && $this->args['user_id'] == get_current_user_id())) ) {
					$nonce = wp_create_nonce( 'user_field_form_'.$field['name'].'_'.$this->args['user_id'] );

					$this->output .= '<div id="'.@$field['name'].'_field_wrap" class="clearfix ap-form-fields-wrap'.$error_class.'">';
						$this->output .= '<label class="ap-form-fields-wrap-label">'.@$field['label'].'</label>';
						$this->output .= '<div id="user_field_form_'.$field['name'].'" class="ap-form-fields-wrap-inner"><span>'.@$field['value'].'</apn></div>';
					$this->output .= '</div>';
				}
			} else {

				switch ( $field['type'] ) {

					case 'text':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->text_field( $field, 'text' );
						$this->output .= '</div>';
						break;

					case 'password':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->text_field( $field, 'password' );
						$this->output .= '</div>';
						break;

					case 'number':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->number_field( $field );
						$this->output .= '</div>';
						break;

					case 'checkbox':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->checkbox_field( $field );
						$this->output .= '</div>';
						break;

					case 'radio':
						$this->output .= '<div class="ap-field-'.@$field['name'] .' ap-form-fields' . $error_class .'">';
						$this->radio_field( $field );
						$this->output .= '</div>';
						break;

					case 'select':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->select_field( $field );
						$this->output .= '</div>';
						break;

					case 'taxonomy_select':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->taxonomy_select_field( $field );
						$this->output .= '</div>';
						break;

					case 'page_select':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->page_select_field( $field );
						$this->output .= '</div>';
						break;

					case 'textarea':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->textarea_field( $field );
						$this->output .= '</div>';
						break;

					case 'editor':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->editor_field( $field );
						$this->output .= '</div>';
						break;

					case 'hidden':
						$this->hidden_field( $field );
						break;

					case 'custom':
						$this->output .= '<div class="ap-field-'.@$field['name'].' ap-form-fields'.$error_class.'">';
						$this->custom_field( $field );
						$this->output .= '</div>';
						break;

					default:
						/**
						 * FILTER: ap_form_fields_[type]
						 * filter for custom form field type
						 */
						$this->output .= apply_filters( 'ap_form_fields_'.$field['type'],  $field );
						break;
				}
			}
		}
	}

	/**
	 * Output form
	 * @return string
	 * @since 2.0.1
	 */
	public function get_form() {

		if ( empty( $this->args['fields'] ) ) {
			return __( 'No fields found', 'anspress-question-answer' ); }

		$this->build();

		return $this->output;
	}

}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Add your comment