array( array( 'key' => 'size', 'type' => 'width', 'label' => __( 'How wide', '2ranq-forms' ), 'help' => __( 'Two half fields sit side by side in one row.', '2ranq-forms' ), 'default' => 'full', 'options' => array( 'full' => __( 'Whole row', '2ranq-forms' ), 'half' => __( 'Half', '2ranq-forms' ), 'third' => __( 'Third', '2ranq-forms' ), ), ), array( 'key' => 'label', 'type' => 'text', 'label' => __( 'Label', '2ranq-forms' ), ), array( 'key' => 'description', 'type' => 'textarea', 'label' => __( 'Description', '2ranq-forms' ), 'help' => __( 'Shown under the field.', '2ranq-forms' ), ), array( 'key' => 'required', 'type' => 'toggle', 'label' => __( 'Required', '2ranq-forms' ), ), ), 'advanced' => array( array( 'key' => 'placeholder', 'type' => 'text', 'label' => __( 'Placeholder', '2ranq-forms' ), ), array( 'key' => 'required_message', 'type' => 'text', 'label' => __( 'Message when empty', '2ranq-forms' ), 'help' => __( 'Leave empty to use the default message.', '2ranq-forms' ), ), array( 'key' => 'label_hidden', 'type' => 'toggle', 'label' => __( 'Hide label', '2ranq-forms' ), ), array( 'key' => 'default_value', 'type' => 'text', 'label' => __( 'Starting value', '2ranq-forms' ), 'help' => __( 'Filled in before the visitor types anything.', '2ranq-forms' ), ), array( 'key' => 'css_class', 'type' => 'text', 'label' => __( 'CSS class', '2ranq-forms' ), ), ), 'logic' => array( array( 'key' => 'conditional', 'type' => 'conditional', 'label' => __( 'Show this field only when', '2ranq-forms' ), 'help' => __( 'Leave empty and the field is always shown.', '2ranq-forms' ), ), ), ); } /** * Prints the field on the site. * * @param array $field The field settings. * @param int $form_id The form id. * * @return void */ abstract public function render( $field, $form_id ); /** * Cleans a value that arrived from a visitor. * * What arrives is never trusted. This is the only point through which a * value enters the plugin. * * @param mixed $value The raw value. * @param array $field The field settings. * * @return mixed */ public function sanitize( $value, $field ) { unset( $field ); return sanitize_text_field( is_scalar( $value ) ? (string) $value : '' ); } /** * Validates the value. Returns an error message, or an empty string when * everything is fine. * * This runs on the server, always, no matter that the browser already * checked the same thing. * * @param mixed $value The cleaned value. * @param array $field The field settings. * * @return string An empty string means it passed. */ public function validate( $value, $field ) { if ( ! empty( $field['required'] ) && '' === trim( (string) $value ) ) { return $this->required_message( $field ); } return ''; } /** * The value prepared for display in the entry and in the email. * * @param mixed $value The cleaned value. * @param array $field The field settings. * * @return string */ public function format_value( $value, $field ) { unset( $field ); return is_array( $value ) ? implode( ', ', array_map( 'strval', $value ) ) : (string) $value; } /** * The message shown when a required field is left empty. * * @param array $field The field settings. * * @return string */ protected function required_message( $field ) { if ( ! empty( $field['required_message'] ) ) { return (string) $field['required_message']; } return __( 'This field is required.', '2ranq-forms' ); } /** * Extra classes on the field wrapper: the width and whatever the person * typed in themselves. * * @param array $field The field settings. * * @return string Starts with a space, or is empty. */ /** * Attributes on the field wrapper: the conditional logic rules. * * They are printed as a plain attribute, so the script reads them and hides * the field right away, while the person is still filling the form in. The * server checks the same rules again. * * @param array $field The field settings. * * @return string Starts with a space, or is empty. */ protected function wrapper_data( $field ) { $logic = Ranq_Forms_Conditions::attribute( $field ); return '' === $logic ? '' : ' data-ranq-cond="' . esc_attr( $logic ) . '"'; } protected function extra_classes( $field ) { $classes = array(); $size = isset( $field['size'] ) ? sanitize_key( $field['size'] ) : 'full'; // A field that failed validation is marked, so it is obvious which one it is. $errors = Ranq_Forms_Submission::get_errors(); $key = $this->field_key( $field ); if ( '' !== $key && isset( $errors[ $key ] ) ) { $classes[] = 'has-error'; } if ( in_array( $size, array( 'half', 'third' ), true ) ) { $classes[] = 'ranq-field--' . $size; } if ( ! empty( $field['css_class'] ) ) { foreach ( preg_split( '/\s+/', (string) $field['css_class'] ) as $custom ) { $custom = sanitize_html_class( $custom ); if ( '' !== $custom ) { $classes[] = $custom; } } } return $classes ? ' ' . implode( ' ', $classes ) : ''; } /** * The name the value arrives under in the request. * * @param array $field The field settings. * * @return string */ protected function input_name( $field ) { return 'ranq_fields[' . $this->field_key( $field ) . ']'; } /** * The key of the field inside the form. * * @param array $field The field settings. * * @return string */ protected function field_key( $field ) { return isset( $field['id'] ) ? sanitize_key( $field['id'] ) : ''; } /** * The value the field shows when the form comes back after a failed send. * * A send can fail long after the visitor wrote their text: a required field * was missed, the spam check said no, the page had been cached for a week. A * blank form at that moment throws the whole message away, and nobody types * it twice. So every field that can, gives the text back. The value is * cleaned by the field's own sanitize(), because what came in is as raw as * any other sent value. Null means there is nothing to give back, and the * field falls back to its default. A password and a file stay out of this on * purpose: a password is never printed back into a page, and a browser does * not allow a file input to be prefilled at all. * * @param array $field The field settings. * @param int $form_id The form id. * * @return mixed The cleaned sent value, or null when there is none. */ protected function sticky_value( $field, $form_id ) { $raw = Ranq_Forms_Submission::posted_raw( $form_id, $this->field_key( $field ) ); if ( null === $raw ) { return null; } return $this->sanitize( $raw, $field ); } /** * The element id in the HTML, has to be unique per form. * * @param array $field The field settings. * @param int $form_id The form id. * * @return string */ protected function input_id( $field, $form_id ) { return 'ranq-field-' . absint( $form_id ) . '-' . $this->field_key( $field ); } /** * Prints the field label above the input. * * @param array $field The field settings. * @param int $form_id The form id. * * @return void */ protected function render_label( $field, $form_id ) { if ( ! empty( $field['label_hidden'] ) || empty( $field['label'] ) ) { return; } ?> input_id( $field, $form_id ) . '-desc'; } }