| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207 |
- <?php
- /**
- * Base field template.
- *
- * @since 1.0.0
- */
- abstract class WPForms_Field {
- /**
- * Full name of the field type, eg "Paragraph Text".
- *
- * @since 1.0.0
- *
- * @var string
- */
- public $name;
- /**
- * Type of the field, eg "textarea".
- *
- * @since 1.0.0
- *
- * @var string
- */
- public $type;
- /**
- * Font Awesome Icon used for the editor button, eg "fa-list".
- *
- * @since 1.0.0
- *
- * @var mixed
- */
- public $icon = false;
- /**
- * Priority order the field button should show inside the "Add Fields" tab.
- *
- * @since 1.0.0
- *
- * @var int
- */
- public $order = 1;
- /**
- * Field group the field belongs to.
- *
- * @since 1.0.0
- *
- * @var string
- */
- public $group = 'standard';
- /**
- * Placeholder to hold default value(s) for some field types.
- *
- * @since 1.0.0
- *
- * @var mixed
- */
- public $defaults;
- /**
- * Current form ID in the admin builder.
- *
- * @since 1.1.1
- *
- * @var int|bool
- */
- public $form_id;
- /**
- * Current field ID.
- *
- * @since 1.5.6
- *
- * @var int
- */
- public $field_id;
- /**
- * Current form data.
- *
- * @since 1.1.1
- *
- * @var array
- */
- public $form_data;
- /**
- * Current field data.
- *
- * @since 1.5.6
- *
- * @var array
- */
- public $field_data;
- /**
- * Primary class constructor.
- *
- * @since 1.0.0
- *
- * @param bool $init Pass false to allow to shortcut the whole initialization, if needed.
- */
- public function __construct( $init = true ) {
- if ( ! $init ) {
- return;
- }
- // The form ID is to be accessed in the builder.
- $this->form_id = isset( $_GET['form_id'] ) ? (int) $_GET['form_id'] : false; // phpcs:ignore WordPress.Security.NonceVerification
- // Bootstrap.
- $this->init();
- // Temporary solution to get an object of the field class.
- add_filter(
- "wpforms_fields_get_field_object_{$this->type}",
- function () {
- return $this;
- }
- );
- // Add fields tab.
- add_filter( 'wpforms_builder_fields_buttons', array( $this, 'field_button' ), 15 );
- // Field options tab.
- add_action( "wpforms_builder_fields_options_{$this->type}", array( $this, 'field_options' ), 10 );
- // Preview fields.
- add_action( "wpforms_builder_fields_previews_{$this->type}", array( $this, 'field_preview' ), 10 );
- // AJAX Add new field.
- add_action( "wp_ajax_wpforms_new_field_{$this->type}", array( $this, 'field_new' ) );
- // Display field input elements on front-end.
- add_action( "wpforms_display_field_{$this->type}", array( $this, 'field_display' ), 10, 3 );
- // Display field on back-end.
- add_filter( "wpforms_pro_admin_entries_edit_is_field_displayable_{$this->type}", '__return_true', 9 );
- // Validation on submit.
- add_action( "wpforms_process_validate_{$this->type}", array( $this, 'validate' ), 10, 3 );
- // Format.
- add_action( "wpforms_process_format_{$this->type}", array( $this, 'format' ), 10, 3 );
- // Prefill.
- add_filter( 'wpforms_field_properties', array( $this, 'field_prefill_value_property' ), 10, 3 );
- // Change the choice's value while saving entries.
- add_filter( 'wpforms_process_before_form_data', [ $this, 'field_fill_empty_choices' ] );
- // Change field name for ajax error.
- add_filter( 'wpforms_process_ajax_error_field_name', [ $this, 'ajax_error_field_name' ], 10, 4 );
- // Add HTML line breaks before all newlines in Entry Preview.
- add_filter( "wpforms_pro_fields_entry_preview_get_field_value_{$this->type}_field_after", 'nl2br', 100 );
- }
- /**
- * All systems go. Used by subclasses. Required.
- *
- * @since 1.0.0
- * @since 1.5.0 Converted to abstract method, as it's required for all fields.
- */
- abstract public function init();
- /**
- * Prefill field value with either fallback or dynamic data.
- * This needs to be public (although internal) to be used in WordPress hooks.
- *
- * @since 1.5.0
- *
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- * @param array $form_data Prepared form data/settings.
- *
- * @return array Modified field properties.
- */
- public function field_prefill_value_property( $properties, $field, $form_data ) {
- // Process only for current field.
- if ( $this->type !== $field['type'] ) {
- return $properties;
- }
- // Set the form data, so we can reuse it later, even on front-end.
- $this->form_data = $form_data;
- // Dynamic data.
- if ( ! empty( $this->form_data['settings']['dynamic_population'] ) ) {
- $properties = $this->field_prefill_value_property_dynamic( $properties, $field );
- }
- // Fallback data, rewrites dynamic because user-submitted data is more important.
- $properties = $this->field_prefill_value_property_fallback( $properties, $field );
- return $properties;
- }
- /**
- * As we are processing user submitted data - ignore all admin-defined defaults.
- * Preprocess choices-related fields only.
- *
- * @since 1.5.0
- *
- * @param array $field Field data and settings.
- * @param array $properties Properties we are modifying.
- */
- public function field_prefill_remove_choices_defaults( $field, &$properties ) {
- // Skip this step on admin page.
- if ( is_admin() && ! wpforms_is_admin_page( 'entries', 'edit' ) ) {
- return;
- }
- if (
- ! empty( $field['dynamic_choices'] ) ||
- ! empty( $field['choices'] )
- ) {
- array_walk_recursive(
- $properties['inputs'],
- function ( &$value, $key ) {
- if ( 'default' === $key ) {
- $value = false;
- }
- if ( 'wpforms-selected' === $value ) {
- $value = '';
- }
- }
- );
- }
- }
- /**
- * Whether current field can be populated dynamically.
- *
- * @since 1.5.0
- *
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return bool
- */
- public function is_dynamic_population_allowed( $properties, $field ) {
- $allowed = true;
- // Allow population on front-end only.
- if ( is_admin() ) {
- $allowed = false;
- }
- // For dynamic population we require $_GET.
- if ( empty( $_GET ) ) { // phpcs:ignore
- $allowed = false;
- }
- return apply_filters( 'wpforms_field_is_dynamic_population_allowed', $allowed, $properties, $field );
- }
- /**
- * Prefill the field value with a dynamic value, that we get from $_GET.
- * The pattern is: wpf4_12_primary, where:
- * 4 - form_id,
- * 12 - field_id,
- * first - input key.
- * As 'primary' is our default input key, "wpf4_12_primary" and "wpf4_12" are the same.
- *
- * @since 1.5.0
- *
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return array Modified field properties.
- */
- protected function field_prefill_value_property_dynamic( $properties, $field ) {
- if ( ! $this->is_dynamic_population_allowed( $properties, $field ) ) {
- return $properties;
- }
- // Iterate over each GET key, parse, and scrap data from there.
- foreach ( $_GET as $key => $raw_value ) { // phpcs:ignore
- preg_match( '/wpf(\d+)_(\d+)(.*)/i', $key, $matches );
- if ( empty( $matches ) || ! is_array( $matches ) ) {
- continue;
- }
- // Required.
- $form_id = absint( $matches[1] );
- $field_id = absint( $matches[2] );
- $input = 'primary';
- // Optional.
- if ( ! empty( $matches[3] ) ) {
- $input = sanitize_key( trim( $matches[3], '_' ) );
- }
- // Both form and field IDs should be the same as current form/field.
- if (
- (int) $this->form_data['id'] !== $form_id ||
- (int) $field['id'] !== $field_id
- ) {
- // Go to the next GET param.
- continue;
- }
- if ( ! empty( $raw_value ) ) {
- $this->field_prefill_remove_choices_defaults( $field, $properties );
- }
- /*
- * Some fields (like checkboxes) support multiple selection.
- * We do not support nested values, so omit them.
- * Example: ?wpf771_19_wpforms[fields][19][address1]=test
- * In this case:
- * $input = wpforms
- * $raw_value = [fields=>[]]
- * $single_value = [19=>[]]
- * There is no reliable way to clean those things out.
- * So we will ignore the value altogether if it's an array.
- * We support only single value numeric arrays, like these:
- * ?wpf771_19[]=test1&wpf771_19[]=test2
- * ?wpf771_19_value[]=test1&wpf771_19_value[]=test2
- * ?wpf771_41_r3_c2[]=1&wpf771_41_r1_c4[]=1
- */
- if ( is_array( $raw_value ) ) {
- foreach ( $raw_value as $single_value ) {
- $properties = $this->get_field_populated_single_property_value( $single_value, $input, $properties, $field );
- }
- } else {
- $properties = $this->get_field_populated_single_property_value( $raw_value, $input, $properties, $field );
- }
- }
- return $properties;
- }
- /**
- * Public version of get_field_populated_single_property_value() to use by external classes.
- *
- * @since 1.6.0.1
- *
- * @param string $raw_value Value from a GET param, always a string.
- * @param string $input Represent a subfield inside the field. May be empty.
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return array Modified field properties.
- */
- public function get_field_populated_single_property_value_public( $raw_value, $input, $properties, $field ) {
- return $this->get_field_populated_single_property_value( $raw_value, $input, $properties, $field );
- }
- /**
- * Get the value, that is used to prefill via dynamic or fallback population.
- * Based on field data and current properties.
- *
- * @since 1.5.0
- *
- * @param string $raw_value Value from a GET param, always a string.
- * @param string $input Represent a subfield inside the field. May be empty.
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return array Modified field properties.
- */
- protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) {
- if ( ! is_string( $raw_value ) ) {
- return $properties;
- }
- $get_value = stripslashes( sanitize_text_field( $raw_value ) );
- // For fields that have dynamic choices we need to add extra logic.
- if ( ! empty( $field['dynamic_choices'] ) ) {
- $properties = $this->get_field_populated_single_property_value_dynamic_choices( $get_value, $properties );
- } elseif ( ! empty( $field['choices'] ) && is_array( $field['choices'] ) ) {
- $properties = $this->get_field_populated_single_property_value_normal_choices( $get_value, $properties, $field );
- } else {
- /*
- * For other types of fields we need to check that
- * the key is registered for the defined field in inputs array.
- */
- if (
- ! empty( $input ) &&
- isset( $properties['inputs'][ $input ] )
- ) {
- $properties['inputs'][ $input ]['attr']['value'] = $get_value;
- }
- }
- return $properties;
- }
- /**
- * Get the value, that is used to prefill via dynamic or fallback population.
- * Based on field data and current properties.
- * Dynamic choices section.
- *
- * @since 1.6.0
- *
- * @param string $get_value Value from a GET param, always a string, sanitized, stripped slashes.
- * @param array $properties Field properties.
- *
- * @return array Modified field properties.
- */
- protected function get_field_populated_single_property_value_dynamic_choices( $get_value, $properties ) {
- $default_key = null;
- foreach ( $properties['inputs'] as $input_key => $input_arr ) {
- // Dynamic choices support only integers in its values.
- if ( absint( $get_value ) === $input_arr['attr']['value'] ) {
- $default_key = $input_key;
- // Stop iterating over choices.
- break;
- }
- }
- // Redefine default choice only if dynamic value has changed anything.
- if ( null !== $default_key ) {
- foreach ( $properties['inputs'] as $input_key => $choice_arr ) {
- if ( $input_key === $default_key ) {
- $properties['inputs'][ $input_key ]['default'] = true;
- $properties['inputs'][ $input_key ]['container']['class'][] = 'wpforms-selected';
- // Stop iterating over choices.
- break;
- }
- }
- }
- return $properties;
- }
- /**
- * Fill choices without labels.
- *
- * @since 1.6.2
- *
- * @param array $form_data Form data.
- *
- * @return array
- */
- public function field_fill_empty_choices( $form_data ) {
- if ( empty( $form_data['fields'] ) ) {
- return $form_data;
- }
- // Set value for choices with the image only. Conditional logic doesn't work without value.
- foreach ( $form_data['fields'] as $field_key => $field ) {
- // Payment fields have their labels set up upfront.
- if ( empty( $field['choices'] ) || ! in_array( $field['type'], [ 'radio', 'checkbox' ], true ) ) {
- continue;
- }
- foreach ( $field['choices'] as $choice_id => $choice ) {
- if ( ( isset( $choice['value'] ) && '' !== trim( $choice['value'] ) ) || empty( $choice['image'] ) ) {
- continue;
- }
- /* translators: %d - choice number. */
- $form_data['fields'][ $field_key ]['choices'][ $choice_id ]['value'] = sprintf( esc_html__( 'Choice %d', 'wpforms-lite' ), (int) $choice_id );
- }
- }
- return $form_data;
- }
- /**
- * Get the value, that is used to prefill via dynamic or fallback population.
- * Based on field data and current properties.
- * Normal choices section.
- *
- * @since 1.6.0
- *
- * @param string $get_value Value from a GET param, always a string, sanitized.
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return array Modified field properties.
- */
- protected function get_field_populated_single_property_value_normal_choices( $get_value, $properties, $field ) {
- $default_key = null;
- // For fields that have normal choices we need to add extra logic.
- foreach ( $field['choices'] as $choice_key => $choice_arr ) {
- $choice_value_key = isset( $field['show_values'] ) ? 'value' : 'label';
- if (
- (
- isset( $choice_arr[ $choice_value_key ] ) &&
- strtoupper( sanitize_text_field( $choice_arr[ $choice_value_key ] ) ) === strtoupper( $get_value )
- ) ||
- (
- empty( $choice_arr[ $choice_value_key ] ) &&
- /* translators: %d - choice number. */
- $get_value === sprintf( esc_html__( 'Choice %d', 'wpforms-lite' ), (int) $choice_key )
- )
- ) {
- $default_key = $choice_key;
- // Stop iterating over choices.
- break;
- }
- }
- // Redefine default choice only if population value has changed anything.
- if ( null !== $default_key ) {
- foreach ( $field['choices'] as $choice_key => $choice_arr ) {
- if ( $choice_key === $default_key ) {
- $properties['inputs'][ $choice_key ]['default'] = true;
- $properties['inputs'][ $choice_key ]['container']['class'][] = 'wpforms-selected';
- break;
- }
- }
- }
- return $properties;
- }
- /**
- * Whether current field can be populated dynamically.
- *
- * @since 1.5.0
- *
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return bool
- */
- public function is_fallback_population_allowed( $properties, $field ) {
- $allowed = true;
- // Allow population on front-end only.
- if ( is_admin() ) {
- $allowed = false;
- }
- /*
- * Commented out to allow partial fail for complex multi-inputs fields.
- * Example: name field with first/last format and being required, filled out only first.
- * On submit we will preserve those sub-inputs that are not empty and display an error for an empty.
- */
- // Do not populate if there are errors for that field.
- /*
- $errors = wpforms()->process->errors;
- if ( ! empty( $errors[ $this->form_data['id'] ][ $field['id'] ] ) ) {
- $allowed = false;
- }
- */
- // Require form id being the same for submitted and currently rendered form.
- if (
- ! empty( $_POST['wpforms']['id'] ) && // phpcs:ignore
- (int) $_POST['wpforms']['id'] !== (int) $this->form_data['id'] // phpcs:ignore
- ) {
- $allowed = false;
- }
- // Require $_POST of submitted field.
- if ( empty( $_POST['wpforms']['fields'] ) ) { // phpcs:ignore
- $allowed = false;
- }
- // Require field (processed and rendered) being the same.
- if ( ! isset( $_POST['wpforms']['fields'][ $field['id'] ] ) ) { // phpcs:ignore
- $allowed = false;
- }
- return apply_filters( 'wpforms_field_is_fallback_population_allowed', $allowed, $properties, $field );
- }
- /**
- * Prefill the field value with a fallback value from form submission (in case of JS validation failed), that we get from $_POST.
- *
- * @since 1.5.0
- *
- * @param array $properties Field properties.
- * @param array $field Current field specific data.
- *
- * @return array Modified field properties.
- */
- protected function field_prefill_value_property_fallback( $properties, $field ) {
- if ( ! $this->is_fallback_population_allowed( $properties, $field ) ) {
- return $properties;
- }
- if ( empty( $_POST['wpforms']['fields'] ) || ! is_array( $_POST['wpforms']['fields'] ) ) { // phpcs:ignore
- return $properties;
- }
- // We got user submitted raw data (not processed, will be done later).
- $raw_value = $_POST['wpforms']['fields'][ $field['id'] ]; // phpcs:ignore
- $input = 'primary';
- if ( ! empty( $raw_value ) ) {
- $this->field_prefill_remove_choices_defaults( $field, $properties );
- }
- /*
- * For this particular field this value may be either array or a string.
- * In array - this is a complex field, like address.
- * The key in array will be a sub-input (address1, state), and its appropriate value.
- */
- if ( is_array( $raw_value ) ) {
- foreach ( $raw_value as $input => $single_value ) {
- $properties = $this->get_field_populated_single_property_value( $single_value, sanitize_key( $input ), $properties, $field );
- }
- } else {
- $properties = $this->get_field_populated_single_property_value( $raw_value, sanitize_key( $input ), $properties, $field );
- }
- return $properties;
- }
- /**
- * Create the button for the 'Add Fields' tab, inside the form editor.
- *
- * @since 1.0.0
- *
- * @param array $fields List of form fields with their data.
- *
- * @return array
- */
- public function field_button( $fields ) {
- // Add field information to fields array.
- $fields[ $this->group ]['fields'][] = array(
- 'order' => $this->order,
- 'name' => $this->name,
- 'type' => $this->type,
- 'icon' => $this->icon,
- );
- // Wipe hands clean.
- return $fields;
- }
- /**
- * Create the field options panel. Used by subclasses.
- *
- * @since 1.0.0
- * @since 1.5.0 Converted to abstract method, as it's required for all fields.
- *
- * @param array $field Field data and settings.
- */
- abstract public function field_options( $field );
- /**
- * Create the field preview. Used by subclasses.
- *
- * @since 1.0.0
- * @since 1.5.0 Converted to abstract method, as it's required for all fields.
- *
- * @param array $field Field data and settings.
- */
- abstract public function field_preview( $field );
- /**
- * Helper function to create field option elements.
- *
- * Field option elements are pieces that help create a field option.
- * They are used to quickly build field options.
- *
- * @since 1.0.0
- *
- * @param string $option Field option to render.
- * @param array $field Field data and settings.
- * @param array $args Field preview arguments.
- * @param bool $echo Print or return the value. Print by default.
- *
- * @return mixed echo or return string
- */
- public function field_element( $option, $field, $args = array(), $echo = true ) {
- $id = (int) $field['id'];
- $class = ! empty( $args['class'] ) ? wpforms_sanitize_classes( (array) $args['class'], true ) : '';
- $slug = ! empty( $args['slug'] ) ? sanitize_title( $args['slug'] ) : '';
- $attrs = '';
- $output = '';
- if ( ! empty( $args['data'] ) ) {
- foreach ( $args['data'] as $arg_key => $val ) {
- if ( is_array( $val ) ) {
- $val = wp_json_encode( $val );
- }
- $attrs .= ' data-' . $arg_key . '=\'' . $val . '\'';
- }
- }
- if ( ! empty( $args['attrs'] ) ) {
- foreach ( $args['attrs'] as $arg_key => $val ) {
- if ( is_array( $val ) ) {
- $val = wp_json_encode( $val );
- }
- $attrs .= $arg_key . '=\'' . $val . '\'';
- }
- }
- switch ( $option ) {
- // Row.
- case 'row':
- $output = sprintf(
- '<div class="wpforms-field-option-row wpforms-field-option-row-%s %s" id="wpforms-field-option-row-%d-%s" data-field-id="%d" %s>%s</div>',
- $slug,
- $class,
- $id,
- $slug,
- $id,
- $attrs,
- $args['content']
- );
- break;
- // Label.
- case 'label':
- $class = ! empty( $class ) ? ' class="' . $class . '"' : '';
- $output = sprintf( '<label for="wpforms-field-option-%d-%s"%s>%s', $id, $slug, $class, esc_html( $args['value'] ) );
- if ( isset( $args['tooltip'] ) && ! empty( $args['tooltip'] ) ) {
- $output .= sprintf( '<i class="fa fa-question-circle-o wpforms-help-tooltip" title="%s"></i>', esc_attr( $args['tooltip'] ) );
- }
- if ( isset( $args['after_tooltip'] ) && ! empty( $args['after_tooltip'] ) ) {
- $output .= $args['after_tooltip'];
- }
- $output .= '</label>';
- break;
- // Text input.
- case 'text':
- $type = ! empty( $args['type'] ) ? esc_attr( $args['type'] ) : 'text';
- $placeholder = ! empty( $args['placeholder'] ) ? esc_attr( $args['placeholder'] ) : '';
- $before = ! empty( $args['before'] ) ? '<span class="before-input">' . esc_html( $args['before'] ) . '</span>' : '';
- if ( ! empty( $before ) ) {
- $class .= ' has-before';
- }
- $output = sprintf( '%s<input type="%s" class="%s" id="wpforms-field-option-%d-%s" name="fields[%d][%s]" value="%s" placeholder="%s" %s>', $before, $type, $class, $id, $slug, $id, $slug, esc_attr( $args['value'] ), $placeholder, $attrs );
- break;
- // Textarea.
- case 'textarea':
- $rows = ! empty( $args['rows'] ) ? (int) $args['rows'] : '3';
- $output = sprintf( '<textarea class="%s" id="wpforms-field-option-%d-%s" name="fields[%d][%s]" rows="%d" %s>%s</textarea>', $class, $id, $slug, $id, $slug, $rows, $attrs, $args['value'] );
- break;
- // Checkbox.
- case 'checkbox':
- $checked = checked( '1', $args['value'], false );
- $output = sprintf( '<input type="checkbox" class="%s" id="wpforms-field-option-%d-%s" name="fields[%d][%s]" value="1" %s %s>', $class, $id, $slug, $id, $slug, $checked, $attrs );
- $output .= empty( $args['nodesc'] ) ? sprintf( '<label for="wpforms-field-option-%d-%s" class="inline">%s', $id, $slug, $args['desc'] ) : '';
- if ( isset( $args['tooltip'] ) && ! empty( $args['tooltip'] ) ) {
- $output .= sprintf( '<i class="fa fa-question-circle-o wpforms-help-tooltip" title="%s"></i>', esc_attr( $args['tooltip'] ) );
- }
- $output .= empty( $args['nodesc'] ) ? '</label>' : '';
- break;
- // Toggle.
- case 'toggle':
- $output = $this->field_element_toggle( $args, $id, $slug, $attrs, $class );
- break;
- // Select.
- case 'select':
- $options = $args['options'];
- $value = isset( $args['value'] ) ? $args['value'] : '';
- $output = sprintf( '<select class="%s" id="wpforms-field-option-%d-%s" name="fields[%d][%s]" %s>', $class, $id, $slug, $id, $slug, $attrs );
- foreach ( $options as $arg_key => $arg_option ) {
- $output .= sprintf( '<option value="%s" %s>%s</option>', esc_attr( $arg_key ), selected( $arg_key, $value, false ), $arg_option );
- }
- $output .= '</select>';
- break;
- }
- if ( ! $echo ) {
- return $output;
- }
- // @todo Ideally, we should late-escape here. All data above seems to be escaped or trusted, but we should consider refactoring this method.
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo $output;
- }
- /**
- * Create field option toggle element.
- *
- * @since 1.6.8
- *
- * @param array $args Arguments.
- * @param integer $id Field ID.
- * @param string $slug Field slug.
- * @param string $attrs Attributes.
- * @param string $class Class.
- *
- * @return string
- */
- private function field_element_toggle( $args, $id, $slug, $attrs, $class ) {
- $input_id = sprintf(
- 'wpforms-field-option-%d-%s',
- esc_attr( $id ),
- esc_attr( $slug )
- );
- $field_name = sprintf(
- 'fields[%d][%s]',
- esc_attr( $id ),
- esc_attr( $slug )
- );
- $label = ! empty( $args['desc'] ) ? $args['desc'] : '';
- $value = ! empty( $args['value'] ) ? $args['value'] : '';
- // Compatibility with the `checkbox` element.
- $args['label-hide'] = ! empty( $args['nodesc'] ) ? $args['nodesc'] : false;
- $args['input-class'] = $class;
- return wpforms_panel_field_toggle_control( $args, $input_id, $field_name, $label, $value, $attrs );
- }
- /**
- * Helper function to create common field options that are used frequently.
- *
- * @since 1.0.0
- *
- * @param string $option Field option to render.
- * @param array $field Field data and settings.
- * @param array $args Field preview arguments.
- * @param bool $echo Print or return the value. Print by default.
- *
- * @return mixed echo or return string
- */
- public function field_option( $option, $field, $args = [], $echo = true ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.MaxExceeded, Generic.Metrics.NestingLevel.MaxExceeded
- $output = '';
- $markup = '';
- switch ( $option ) {
- /**
- * Basic Fields.
- */
- /*
- * Basic Options markup.
- */
- case 'basic-options':
- $markup = ! empty( $args['markup'] ) ? $args['markup'] : 'open';
- $class = ! empty( $args['class'] ) ? esc_html( $args['class'] ) : '';
- if ( $markup === 'open' ) {
- $output = sprintf(
- '<div class="wpforms-field-option-field-title">%3$s <span>(ID #%1$d)</span></div>
- <div class="wpforms-field-option-group wpforms-field-option-group-basic active" id="wpforms-field-option-basic-%1$d">
- <a href="#" class="wpforms-field-option-group-toggle">%2$s</a>
- <div class="wpforms-field-option-group-inner %4$s">
- ',
- absint( $field['id'] ),
- esc_html__( 'General', 'wpforms-lite' ),
- esc_html( $this->name ),
- esc_attr( $class )
- );
- } else {
- $output = '</div></div>';
- }
- break;
- /*
- * Field Label.
- */
- case 'label':
- $value = ! empty( $field['label'] ) ? esc_html( $field['label'] ) : '';
- $tooltip = esc_html__( 'Enter text for the form field label. Field labels are recommended and can be hidden in the Advanced Settings.', 'wpforms-lite' );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'label', 'value' => esc_html__( 'Label', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'text', $field, array( 'slug' => 'label', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'label', 'content' => $output ), false );
- break;
- /*
- * Field Description.
- */
- case 'description':
- $value = ! empty( $field['description'] ) ? esc_html( $field['description'] ) : '';
- $tooltip = esc_html__( 'Enter text for the form field description.', 'wpforms-lite' );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'description', 'value' => esc_html__( 'Description', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'textarea', $field, array( 'slug' => 'description', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'description', 'content' => $output ), false );
- break;
- /*
- * Field Required toggle.
- */
- case 'required':
- $default = ! empty( $args['default'] ) ? $args['default'] : '0';
- $value = isset( $field['required'] ) ? esc_attr( $field['required'] ) : esc_attr( $default );
- $tooltip = esc_html__( 'Check this option to mark the field required. A form will not submit unless all required fields are provided.', 'wpforms-lite' );
- $output = $this->field_element(
- 'toggle',
- $field,
- [
- 'slug' => 'required',
- 'value' => $value,
- 'desc' => esc_html__( 'Required', 'wpforms-lite' ),
- 'tooltip' => $tooltip,
- ],
- false
- );
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'required',
- 'content' => $output,
- ],
- false
- );
- break;
- /*
- * Field Meta (field type and ID).
- */
- case 'meta':
- _deprecated_argument( __CLASS__ . '::' . __METHOD__ . '( [ \'slug\' => \'meta\' ] )', '1.7.1' );
- $output = sprintf( '<label>%s</label>', esc_html__( 'Type', 'wpforms-lite' ) );
- $output .= sprintf(
- '<p class="meta">%s <span class="id">(ID #%d)</span></p>',
- esc_attr( $this->name ),
- absint( $field['id'] )
- );
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'meta',
- 'content' => $output,
- ],
- false
- );
- break;
- /*
- * Code Block.
- */
- case 'code':
- $value = ! empty( $field['code'] ) ? esc_textarea( $field['code'] ) : '';
- $tooltip = esc_html__( 'Enter code for the form field.', 'wpforms-lite' );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'code', 'value' => esc_html__( 'Code', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'textarea', $field, array( 'slug' => 'code', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'code', 'content' => $output ), false );
- break;
- /*
- * Choices.
- */
- case 'choices':
- $values = ! empty( $field['choices'] ) ? $field['choices'] : $this->defaults;
- $label = ! empty( $args['label'] ) ? esc_html( $args['label'] ) : esc_html__( 'Choices', 'wpforms-lite' );
- $class = array();
- $field_type = $this->type;
- if ( ! empty( $field['multiple'] ) ) {
- $field_type = 'checkbox';
- }
- if ( ! empty( $field['show_values'] ) ) {
- $class[] = 'show-values';
- }
- if ( ! empty( $field['dynamic_choices'] ) ) {
- $class[] = 'wpforms-hidden';
- }
- if ( ! empty( $field['choices_images'] ) ) {
- $class[] = 'show-images';
- }
- // Field label.
- $lbl = $this->field_element(
- 'label',
- $field,
- array(
- 'slug' => 'choices',
- 'value' => $label,
- 'tooltip' => esc_html__( 'Add choices for the form field.', 'wpforms-lite' ),
- 'after_tooltip' => '<a href="#" class="toggle-bulk-add-display toggle-unfoldable-cont"><i class="fa fa-download"></i><span>' . esc_html__( 'Bulk Add', 'wpforms-lite' ) . '</span></a>',
- ),
- false
- );
- // Field contents.
- $fld = sprintf(
- '<ul data-next-id="%s" class="choices-list %s" data-field-id="%d" data-field-type="%s">',
- max( array_keys( $values ) ) + 1,
- wpforms_sanitize_classes( $class, true ),
- absint( $field['id'] ),
- esc_attr( $this->type )
- );
- foreach ( $values as $key => $value ) {
- $default = ! empty( $value['default'] ) ? $value['default'] : '';
- $base = sprintf( 'fields[%s][choices][%s]', absint( $field['id'] ), sanitize_key( $key ) );
- $image = ! empty( $value['image'] ) ? $value['image'] : '';
- $hide_image_btn = false;
- $fld .= '<li data-key="' . absint( $key ) . '">';
- $fld .= sprintf(
- '<input type="%s" name="%s[default]" class="default" value="1" %s>',
- $field_type === 'checkbox' ? 'checkbox' : 'radio',
- esc_attr( $base ),
- checked( '1', $default, false )
- );
- $fld .= '<span class="move"><i class="fa fa-bars"></i></span>';
- $fld .= sprintf(
- '<input type="text" name="%s[label]" value="%s" class="label">',
- esc_attr( $base ),
- esc_attr( $value['label'] )
- );
- $fld .= '<a class="add" href="#"><i class="fa fa-plus-circle"></i></a><a class="remove" href="#"><i class="fa fa-minus-circle"></i></a>';
- $fld .= sprintf(
- '<input type="text" name="%s[value]" value="%s" class="value">',
- esc_attr( $base ),
- esc_attr( ! isset( $value['value'] ) ? '' : $value['value'] )
- );
- $fld .= '<div class="wpforms-image-upload">';
- $fld .= '<div class="preview">';
- if ( ! empty( $image ) ) {
- $fld .= sprintf(
- '<img src="%s"><a href="#" title="%s" class="wpforms-image-upload-remove"><i class="fa fa-trash-o"></i></a>',
- esc_url_raw( $image ),
- esc_attr__( 'Remove Image', 'wpforms-lite' )
- );
- $hide_image_btn = true;
- }
- $fld .= '</div>';
- $fld .= sprintf(
- '<button class="wpforms-btn wpforms-btn-sm wpforms-btn-blue wpforms-btn-block wpforms-image-upload-add" data-after-upload="hide"%s>%s</button>',
- $hide_image_btn ? ' style="display:none;"' : '',
- esc_html__( 'Upload Image', 'wpforms-lite' )
- );
- $fld .= sprintf(
- '<input type="hidden" name="%s[image]" value="%s" class="source">',
- esc_attr( $base ),
- esc_url_raw( $image )
- );
- $fld .= '</div>';
- $fld .= '</li>';
- }
- $fld .= '</ul>';
- // Field note: dynamic status.
- $source = '';
- $type = '';
- $dynamic = ! empty( $field['dynamic_choices'] ) ? esc_html( $field['dynamic_choices'] ) : '';
- if ( 'post_type' === $dynamic && ! empty( $field[ 'dynamic_' . $dynamic ] ) ) {
- $type = esc_html__( 'post type', 'wpforms-lite' );
- $pt = get_post_type_object( $field[ 'dynamic_' . $dynamic ] );
- $source = '';
- if ( null !== $pt ) {
- $source = $pt->labels->name;
- }
- } elseif ( 'taxonomy' === $dynamic && ! empty( $field[ 'dynamic_' . $dynamic ] ) ) {
- $type = esc_html__( 'taxonomy', 'wpforms-lite' );
- $tax = get_taxonomy( $field[ 'dynamic_' . $dynamic ] );
- $source = '';
- if ( false !== $tax ) {
- $source = $tax->labels->name;
- }
- }
- $note = sprintf(
- '<div class="wpforms-alert-warning wpforms-alert %s">',
- ! empty( $dynamic ) && ! empty( $field[ 'dynamic_' . $dynamic ] ) ? '' : 'wpforms-hidden'
- );
- $note .= '<h4>' . esc_html__( 'Dynamic Choices Active', 'wpforms-lite' ) . '</h4>';
- $note .= sprintf(
- /* translators: %1$s - source name; %2$s - type name. */
- '<p>' . esc_html__( 'Choices are dynamically populated from the %1$s %2$s. Go to the Advanced tab to change this.', 'wpforms-lite' ) . '</p>',
- '<span class="dynamic-name">' . esc_html( $source ) . '</span>',
- '<span class="dynamic-type">' . esc_html( $type ) . '</span>'
- );
- $note .= '</div>';
- // Final field output.
- $output = $this->field_element(
- 'row',
- $field,
- array(
- 'slug' => 'choices',
- 'content' => $lbl . $fld . $note,
- ),
- false
- );
- break;
- /*
- * Choices for payments.
- */
- case 'choices_payments':
- $values = ! empty( $field['choices'] ) ? $field['choices'] : $this->defaults;
- $class = array();
- $input_type = in_array( $field['type'], array( 'payment-multiple', 'payment-select' ), true ) ? 'radio' : 'checkbox';
- if ( ! empty( $field['choices_images'] ) ) {
- $class[] = 'show-images';
- }
- // Field label.
- $lbl = $this->field_element(
- 'label',
- $field,
- array(
- 'slug' => 'choices',
- 'value' => esc_html__( 'Items', 'wpforms-lite' ),
- 'tooltip' => esc_html__( 'Add choices for the form field.', 'wpforms-lite' ),
- ),
- false
- );
- // Field contents.
- $fld = sprintf(
- '<ul data-next-id="%s" class="choices-list %s" data-field-id="%d" data-field-type="%s">',
- max( array_keys( $values ) ) + 1,
- wpforms_sanitize_classes( $class, true ),
- absint( $field['id'] ),
- esc_attr( $this->type )
- );
- foreach ( $values as $key => $value ) {
- $default = ! empty( $value['default'] ) ? $value['default'] : '';
- $base = sprintf( 'fields[%s][choices][%s]', absint( $field['id'] ), esc_attr( $key ) );
- $image = ! empty( $value['image'] ) ? $value['image'] : '';
- $hide_image_btn = false;
- $fld .= '<li data-key="' . absint( $key ) . '">';
- $fld .= sprintf(
- '<input type="%s" name="%s[default]" class="default" value="1" %s>',
- esc_attr( $input_type ),
- esc_attr( $base ),
- checked( '1', $default, false )
- );
- $fld .= '<span class="move"><i class="fa fa-bars"></i></span>';
- $fld .= sprintf(
- '<input type="text" name="%s[label]" value="%s" class="label">',
- esc_attr( $base ),
- esc_attr( $value['label'] )
- );
- $fld .= sprintf(
- '<input type="text" name="%s[value]" value="%s" class="value wpforms-money-input" placeholder="%s">',
- esc_attr( $base ),
- esc_attr( $value['value'] ),
- wpforms_format_amount( 0 )
- );
- $fld .= '<a class="add" href="#"><i class="fa fa-plus-circle"></i></a><a class="remove" href="#"><i class="fa fa-minus-circle"></i></a>';
- $fld .= '<div class="wpforms-image-upload">';
- $fld .= '<div class="preview">';
- if ( ! empty( $image ) ) {
- $fld .= sprintf(
- '<img src="%s"><a href="#" title="%s" class="wpforms-image-upload-remove"><i class="fa fa-trash-o"></i></a>',
- esc_url_raw( $image ),
- esc_attr__( 'Remove Image', 'wpforms-lite' )
- );
- $hide_image_btn = true;
- }
- $fld .= '</div>';
- $fld .= sprintf(
- '<button class="wpforms-btn wpforms-btn-sm wpforms-btn-blue wpforms-btn-block wpforms-image-upload-add" data-after-upload="hide"%s>%s</button>',
- $hide_image_btn ? ' style="display:none;"' : '',
- esc_html__( 'Upload Image', 'wpforms-lite' )
- );
- $fld .= sprintf(
- '<input type="hidden" name="%s[image]" value="%s" class="source">',
- $base,
- esc_url_raw( $image )
- );
- $fld .= '</div>';
- $fld .= '</li>';
- }
- $fld .= '</ul>';
- // Final field output.
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'choices',
- 'content' => $lbl . $fld,
- ],
- false
- );
- break;
- /*
- * Choices Images.
- */
- case 'choices_images':
- // Field note: Image tips.
- $note = sprintf(
- '<div class="wpforms-alert-warning wpforms-alert %s">',
- ! empty( $field['choices_images'] ) ? '' : 'wpforms-hidden'
- );
- $note .= wp_kses( /* translators: %s - URL to the ActiveCampaign Getting started page. */
- __( '<h4>Images are not cropped or resized.</h4><p>For best results, they should be the same size and 250x250 pixels or smaller.</p>', 'wpforms-lite' ),
- [
- 'h4' => [],
- 'p' => [],
- ]
- );
- $note .= '</div>';
- // Field contents.
- $fld = $this->field_element(
- 'toggle',
- $field,
- [
- 'slug' => 'choices_images',
- 'value' => isset( $field['choices_images'] ) ? '1' : '0',
- 'desc' => esc_html__( 'Use image choices', 'wpforms-lite' ),
- 'tooltip' => esc_html__( 'Check this option to enable using images with the choices.', 'wpforms-lite' ),
- ],
- false
- );
- // Final field output.
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'choices_images',
- 'class' => ! empty( $field['dynamic_choices'] ) ? 'wpforms-hidden' : '',
- 'content' => $note . $fld,
- ],
- false
- );
- break;
- /*
- * Choices Images Style.
- */
- case 'choices_images_style':
- // Field label.
- $lbl = $this->field_element(
- 'label',
- $field,
- array(
- 'slug' => 'choices_images_style',
- 'value' => esc_html__( 'Image Choice Style', 'wpforms-lite' ),
- 'tooltip' => esc_html__( 'Select the style for the image choices.', 'wpforms-lite' ),
- ),
- false
- );
- // Field contents.
- $fld = $this->field_element(
- 'select',
- $field,
- array(
- 'slug' => 'choices_images_style',
- 'value' => ! empty( $field['choices_images_style'] ) ? esc_attr( $field['choices_images_style'] ) : 'modern',
- 'options' => array(
- 'modern' => esc_html__( 'Modern', 'wpforms-lite' ),
- 'classic' => esc_html__( 'Classic', 'wpforms-lite' ),
- 'none' => esc_html__( 'None', 'wpforms-lite' ),
- ),
- ),
- false
- );
- // Final field output.
- $output = $this->field_element(
- 'row',
- $field,
- array(
- 'slug' => 'choices_images_style',
- 'content' => $lbl . $fld,
- 'class' => ! empty( $field['choices_images'] ) ? '' : 'wpforms-hidden',
- ),
- false
- );
- break;
- /**
- * Advanced Fields.
- */
- /*
- * Default value.
- */
- case 'default_value':
- $value = ! empty( $field['default_value'] ) || ( isset( $field['default_value'] ) && '0' === (string) $field['default_value'] ) ? esc_attr( $field['default_value'] ) : '';
- $tooltip = esc_html__( 'Enter text for the default form field value.', 'wpforms-lite' );
- $toggle = '<a href="#" class="toggle-smart-tag-display toggle-unfoldable-cont" data-type="other"><i class="fa fa-tags"></i><span>' . esc_html__( 'Show Smart Tags', 'wpforms-lite' ) . '</span></a>';
- $output = $this->field_element( 'label', $field, array( 'slug' => 'default_value', 'value' => esc_html__( 'Default Value', 'wpforms-lite' ), 'tooltip' => $tooltip, 'after_tooltip' => $toggle ), false );
- $output .= $this->field_element( 'text', $field, array( 'slug' => 'default_value', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'default_value', 'content' => $output ), false );
- break;
- /*
- * Size.
- */
- case 'size':
- $value = ! empty( $field['size'] ) ? esc_attr( $field['size'] ) : 'medium';
- $class = ! empty( $args['class'] ) ? esc_html( $args['class'] ) : '';
- $tooltip = esc_html__( 'Select the default form field size.', 'wpforms-lite' );
- $options = array(
- 'small' => esc_html__( 'Small', 'wpforms-lite' ),
- 'medium' => esc_html__( 'Medium', 'wpforms-lite' ),
- 'large' => esc_html__( 'Large', 'wpforms-lite' ),
- );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'size', 'value' => esc_html__( 'Field Size', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'select', $field, array( 'slug' => 'size', 'value' => $value, 'options' => $options ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'size', 'content' => $output, 'class' => $class ), false );
- break;
- /*
- * Advanced Options markup.
- */
- case 'advanced-options':
- $markup = ! empty( $args['markup'] ) ? $args['markup'] : 'open';
- if ( $markup === 'open' ) {
- $override = apply_filters( 'wpforms_advanced_options_override', false );
- $override = ! empty( $override ) ? 'style="display:' . $override . ';"' : '';
- $output = sprintf( '<div class="wpforms-field-option-group wpforms-field-option-group-advanced" id="wpforms-field-option-advanced-%d" %s>', absint( $field['id'] ), $override );
- $output .= sprintf( '<a href="#" class="wpforms-field-option-group-toggle">%s</a>', esc_html__( 'Advanced', 'wpforms-lite' ) );
- $output .= '<div class="wpforms-field-option-group-inner">';
- } else {
- $output = '</div></div>';
- }
- break;
- /*
- * Placeholder.
- */
- case 'placeholder':
- $value = ! empty( $field['placeholder'] ) ? esc_attr( $field['placeholder'] ) : '';
- $tooltip = esc_html__( 'Enter text for the form field placeholder.', 'wpforms-lite' );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'placeholder', 'value' => esc_html__( 'Placeholder Text', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'text', $field, array( 'slug' => 'placeholder', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'placeholder', 'content' => $output ), false );
- break;
- /*
- * CSS classes.
- */
- case 'css':
- $toggle = '';
- $value = ! empty( $field['css'] ) ? esc_attr( $field['css'] ) : '';
- $tooltip = esc_html__( 'Enter CSS class names for the form field container. Class names should be separated with spaces.', 'wpforms-lite' );
- if ( 'pagebreak' !== $field['type'] ) {
- $toggle = '<a href="#" class="toggle-layout-selector-display toggle-unfoldable-cont"><i class="fa fa-th-large"></i><span>' . esc_html__( 'Show Layouts', 'wpforms-lite' ) . '</span></a>';
- }
- // Build output.
- $output = $this->field_element( 'label', $field, array( 'slug' => 'css', 'value' => esc_html__( 'CSS Classes', 'wpforms-lite' ), 'tooltip' => $tooltip, 'after_tooltip' => $toggle ), false );
- $output .= $this->field_element( 'text', $field, array( 'slug' => 'css', 'value' => $value ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'css', 'content' => $output ), false );
- break;
- /*
- * Hide Label.
- */
- case 'label_hide':
- $value = isset( $field['label_hide'] ) ? $field['label_hide'] : '0';
- $tooltip = esc_html__( 'Check this option to hide the form field label.', 'wpforms-lite' );
- // Build output.
- $output = $this->field_element(
- 'toggle',
- $field,
- [
- 'slug' => 'label_hide',
- 'value' => $value,
- 'desc' => esc_html__( 'Hide Label', 'wpforms-lite' ),
- 'tooltip' => $tooltip,
- ],
- false
- );
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'label_hide',
- 'content' => $output,
- ],
- false
- );
- break;
- /*
- * Hide sublabels.
- */
- case 'sublabel_hide':
- $value = isset( $field['sublabel_hide'] ) ? $field['sublabel_hide'] : '0';
- $tooltip = esc_html__( 'Check this option to hide the form field sublabel.', 'wpforms-lite' );
- // Build output.
- $output = $this->field_element(
- 'toggle',
- $field,
- [
- 'slug' => 'sublabel_hide',
- 'value' => $value,
- 'desc' => esc_html__( 'Hide Sublabels', 'wpforms-lite' ),
- 'tooltip' => $tooltip,
- ],
- false
- );
- $output = $this->field_element(
- 'row',
- $field,
- [
- 'slug' => 'sublabel_hide',
- 'content' => $output,
- ],
- false
- );
- break;
- /*
- * Input Columns.
- */
- case 'input_columns':
- $value = ! empty( $field['input_columns'] ) ? esc_attr( $field['input_columns'] ) : '';
- $tooltip = esc_html__( 'Select the layout for displaying field choices.', 'wpforms-lite' );
- $options = array(
- '' => esc_html__( 'One Column', 'wpforms-lite' ),
- '2' => esc_html__( 'Two Columns', 'wpforms-lite' ),
- '3' => esc_html__( 'Three Columns', 'wpforms-lite' ),
- 'inline' => esc_html__( 'Inline', 'wpforms-lite' ),
- );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'input_columns', 'value' => esc_html__( 'Choice Layout', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'select', $field, array( 'slug' => 'input_columns', 'value' => $value, 'options' => $options ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'input_columns', 'content' => $output ), false );
- break;
- /*
- * Dynamic Choices.
- */
- case 'dynamic_choices':
- $value = ! empty( $field['dynamic_choices'] ) ? esc_attr( $field['dynamic_choices'] ) : '';
- $tooltip = esc_html__( 'Select auto-populate method to use.', 'wpforms-lite' );
- $options = array(
- '' => esc_html__( 'Off', 'wpforms-lite' ),
- 'post_type' => esc_html__( 'Post Type', 'wpforms-lite' ),
- 'taxonomy' => esc_html__( 'Taxonomy', 'wpforms-lite' ),
- );
- $output = $this->field_element( 'label', $field, array( 'slug' => 'dynamic_choices', 'value' => esc_html__( 'Dynamic Choices', 'wpforms-lite' ), 'tooltip' => $tooltip ), false );
- $output .= $this->field_element( 'select', $field, array( 'slug' => 'dynamic_choices', 'value' => $value, 'options' => $options ), false );
- $output = $this->field_element( 'row', $field, array( 'slug' => 'dynamic_choices', 'content' => $output ), false );
- break;
- /*
- * Dynamic Choices Source.
- */
- case 'dynamic_choices_source':
- $output = '';
- $type = ! empty( $field['dynamic_choices'] ) ? esc_attr( $field['dynamic_choices'] ) : '';
- if ( ! empty( $type ) ) {
- $type_name = '';
- $items = array();
- if ( 'post_type' === $type ) {
- $type_name = esc_html__( 'Post Type', 'wpforms-lite' );
- $items = get_post_types(
- array(
- 'public' => true,
- ),
- 'objects'
- );
- unset( $items['attachment'] );
- } elseif ( 'taxonomy' === $type ) {
- $type_name = esc_html__( 'Taxonomy', 'wpforms-lite' );
- $items = get_taxonomies(
- array(
- 'public' => true,
- ),
- 'objects'
- );
- unset( $items['post_format'] );
- }
- /* translators: %s - dynamic source type name. */
- $tooltip = sprintf( esc_html__( 'Select %s to use for auto-populating field choices.', 'wpforms-lite' ), esc_html( $type_name ) );
- /* translators: %s - dynamic source type name. */
- $label = sprintf( esc_html__( 'Dynamic %s Source', 'wpforms-lite' ), esc_html( $type_name ) );
- $options = array();
- $source = ! empty( $field[ 'dynamic_' . $type ] ) ? esc_attr( $field[ 'dynamic_' . $type ] ) : '';
- foreach ( $items as $key => $item ) {
- $options[ $key ] = esc_html( $item->labels->name );
- }
- // Field option label.
- $option_label = $this->field_element(
- 'label',
- $field,
- array(
- 'slug' => 'dynamic_' . $type,
- 'value' => $label,
- 'tooltip' => $tooltip,
- ),
- false
- );
- // Field option select input.
- $option_input = $this->field_element(
- 'select',
- $field,
- array(
- 'slug' => 'dynamic_' . $type,
- 'options' => $options,
- 'value' => $source,
- ),
- false
- );
- // Field option row (markup) including label and input.
- $output = $this->field_element(
- 'row',
- $field,
- array(
- 'slug' => 'dynamic_' . $type,
- 'content' => $option_label . $option_input,
- ),
- false
- );
- } // End if().
- break;
- }
- if ( ! $echo ) {
- return $output;
- }
- if ( ! in_array( $option, [ 'basic-options', 'advanced-options' ], true ) ) {
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo $output;
- return;
- }
- if ( $markup === 'open' ) {
- do_action( "wpforms_field_options_before_{$option}", $field, $this );
- }
- if ( $markup === 'close' ) {
- do_action( "wpforms_field_options_bottom_{$option}", $field, $this );
- }
- // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo $output;
- if ( $markup === 'open' ) {
- do_action( "wpforms_field_options_top_{$option}", $field, $this );
- }
- if ( $markup === 'close' ) {
- do_action( "wpforms_field_options_after_{$option}", $field, $this );
- }
- }
- /**
- * Helper function to create common field options that are used frequently
- * in the field preview.
- *
- * @since 1.0.0
- * @since 1.5.0 Added support for <select> HTML tag for choices.
- * @since 1.6.1 Added multiple select support.
- *
- * @param string $option Field option to render.
- * @param array $field Field data and settings.
- * @param array $args Field preview arguments.
- * @param bool $echo Print or return the value. Print by default.
- *
- * @return mixed Print or return a string.
- */
- public function field_preview_option( $option, $field, $args = array(), $echo = true ) {
- $output = '';
- $class = ! empty( $args['class'] ) ? wpforms_sanitize_classes( $args['class'] ) : '';
- $allowed_tags = wpforms_builder_preview_get_allowed_tags();
- switch ( $option ) {
- case 'label':
- $label = isset( $field['label'] ) && ! empty( $field['label'] ) ? esc_html( $field['label'] ) : esc_html__( 'Empty Label', 'wpforms-lite' );
- $label_hidden = esc_html__( 'Label Hidden', 'wpforms-lite' );
- $label_empty = esc_html__( 'To ensure your form is accessible, every field should have a descriptive label. If you\'d like to hide the label, you can do so by enabling Hide Label in the Advanced Field Options tab.', 'wpforms-lite' );
- $output = sprintf(
- '<label class="label-title %s"><span class="hidden_text" title="%s"><i class="fa fa-eye-slash"></i></span><span class="empty_text" title="%s"><i class="fa fa-exclamation-triangle"></i></span><span class="text">%s</span><span class="required">*</span></label>',
- $class,
- $label_hidden,
- $label_empty,
- $label
- );
- break;
- case 'description':
- $description = isset( $field['description'] ) && ! empty( $field['description'] ) ? wp_kses( $field['description'], $allowed_tags ) : '';
- $description = strpos( $class, 'nl2br' ) !== false ? nl2br( $description ) : $description;
- $output = sprintf( '<div class="description %s">%s</div>', $class, $description );
- break;
- case 'choices':
- $fields_w_choices = [ 'checkbox', 'gdpr-checkbox', 'select', 'payment-select', 'radio', 'payment-multiple', 'payment-checkbox' ];
- $values = ! empty( $field['choices'] ) ? $field['choices'] : $this->defaults;
- $dynamic = ! empty( $field['dynamic_choices'] ) ? $field['dynamic_choices'] : false;
- $total = count( $values );
- $values = array_slice( $values, 0, 20 );
- /*
- * Check to see if this field is configured for Dynamic Choices,
- * either auto populating from a post type or a taxonomy.
- */
- if ( ! empty( $field['dynamic_post_type'] ) || ! empty( $field['dynamic_taxonomy'] ) ) {
- switch ( $dynamic ) {
- case 'post_type':
- // Post type dynamic populating.
- $total_obj = wp_count_posts( $field['dynamic_post_type'] );
- $total = isset( $total_obj->publish ) ? (int) $total_obj->publish : 0;
- $values = [];
- $posts = wpforms_get_hierarchical_object(
- apply_filters(
- 'wpforms_dynamic_choice_post_type_args',
- [
- 'post_type' => $field['dynamic_post_type'],
- 'posts_per_page' => 20,
- 'orderby' => 'title',
- 'order' => 'ASC',
- ],
- $field,
- $this->form_id
- ),
- true
- );
- foreach ( $posts as $post ) {
- $values[] = [
- 'label' => $post->post_title,
- ];
- }
- break;
- case 'taxonomy':
- // Taxonomy dynamic populating.
- $total = (int) wp_count_terms( $field['dynamic_taxonomy'] );
- $values = [];
- $terms = wpforms_get_hierarchical_object(
- apply_filters(
- 'wpforms_dynamic_choice_taxonomy_args',
- [
- 'taxonomy' => $field['dynamic_taxonomy'],
- 'hide_empty' => false,
- 'number' => 20,
- ],
- $field,
- $this->form_id
- ),
- true
- );
- foreach ( $terms as $term ) {
- $values[] = [
- 'label' => $term->name,
- ];
- }
- break;
- }
- }
- // Notify if dynamic choices source is currently empty.
- if ( empty( $values ) ) {
- $values = [
- [
- 'label' => esc_html__( '(empty)', 'wpforms-lite' ),
- ],
- ];
- }
- // Build output.
- if ( ! in_array( $field['type'], $fields_w_choices, true ) ) {
- break;
- }
- switch ( $field['type'] ) {
- case 'checkbox':
- case 'gdpr-checkbox':
- case 'payment-checkbox':
- $type = 'checkbox';
- break;
- case 'select':
- case 'payment-select':
- $type = 'select';
- break;
- default:
- $type = 'radio';
- break;
- }
- $list_class = [ 'primary-input' ];
- $with_images = empty( $field['dynamic_choices'] ) && ! empty( $field['choices_images'] );
- if ( $with_images ) {
- $list_class[] = 'wpforms-image-choices';
- $list_class[] = 'wpforms-image-choices-' . sanitize_html_class( $field['choices_images_style'] );
- }
- if ( ! empty( $class ) ) {
- $list_class[] = $class;
- }
- // Special rules for <select>-based fields.
- if ( $type === 'select' ) {
- $multiple = ! empty( $field['multiple'] ) ? ' multiple' : '';
- $placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : '';
- $output = sprintf(
- '<select class="%s"%s readonly>',
- wpforms_sanitize_classes( $list_class, true ),
- $multiple
- );
- // Optional placeholder.
- if ( ! empty( $placeholder ) ) {
- $output .= sprintf(
- '<option value="" class="placeholder">%s</option>',
- esc_html( $placeholder )
- );
- }
- // Build the select options.
- foreach ( $values as $key => $value ) {
- $default = isset( $value['default'] ) ? (bool) $value['default'] : false;
- $selected = ! empty( $placeholder ) && empty( $multiple ) ? '' : selected( true, $default, false );
- $label = isset( $value['label'] ) ? trim( $value['label'] ) : '';
- /* translators: %d - Choice item number. */
- $label = $label !== '' ? $label : sprintf( esc_html__( 'Choice %d', 'wpforms-lite' ), (int) $key );
- $label .= ! empty( $field['show_price_after_labels'] ) && isset( $value['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $value['value'] ), true ) : '';
- $output .= sprintf(
- '<option value="%2$s" %1$s>%2$s</option>',
- $selected,
- esc_html( $label )
- );
- }
- $output .= '</select>';
- } else {
- // Normal checkbox/radio-based fields.
- $output = sprintf(
- '<ul class="%s">',
- wpforms_sanitize_classes( $list_class, true )
- );
- foreach ( $values as $key => $value ) {
- $default = isset( $value['default'] ) ? $value['default'] : '';
- $selected = checked( '1', $default, false );
- $input_class = [];
- $item_class = [];
- if ( ! empty( $value['default'] ) ) {
- $item_class[] = 'wpforms-selected';
- }
- if ( $with_images ) {
- $item_class[] = 'wpforms-image-choices-item';
- }
- $output .= sprintf(
- '<li class="%s">',
- wpforms_sanitize_classes( $item_class, true )
- );
- $label = isset( $value['label'] ) ? trim( $value['label'] ) : '';
- /* translators: %d - Choice item number. */
- $label = $label !== '' ? $label : sprintf( esc_html__( 'Choice %d', 'wpforms-lite' ), (int) $key );
- $label .= ! empty( $field['show_price_after_labels'] ) && isset( $value['value'] ) ? ' - ' . wpforms_format_amount( wpforms_sanitize_amount( $value['value'] ), true ) : '';
- if ( $with_images ) {
- if ( in_array( $field['choices_images_style'], [ 'modern', 'classic' ], true ) ) {
- $input_class[] = 'wpforms-screen-reader-element';
- }
- $output .= '<label>';
- $output .= sprintf(
- '<span class="wpforms-image-choices-image"><img src="%s" alt="%s"%s></span>',
- ! empty( $value['image'] ) ? esc_url( $value['image'] ) : WPFORMS_PLUGIN_URL . 'assets/images/builder/placeholder-200x125.svg',
- esc_attr( $value['label'] ),
- ! empty( $value['label'] ) ? ' title="' . esc_attr( $value['label'] ) . '"' : ''
- );
- if ( $field['choices_images_style'] === 'none' ) {
- $output .= '<br>';
- }
- $output .= sprintf(
- '<input type="%s" class="%s" %s readonly>',
- $type,
- wpforms_sanitize_classes( $input_class, true ),
- $selected
- );
- $output .= '<span class="wpforms-image-choices-label">' . wp_kses( $label, $allowed_tags ) . '</span>';
- $output .= '</label>';
- } else {
- $output .= sprintf(
- '<input type="%s" %s readonly> %s',
- $type,
- $selected,
- wp_kses( $label, $allowed_tags )
- );
- }
- $output .= '</li>';
- }
- $output .= '</ul>';
- /*
- * Contains more than 20 items, include a note about a limited subset of results displayed.
- */
- if ( $total > 20 ) {
- $output .= '<div class="wpforms-alert-dynamic wpforms-alert wpforms-alert-warning">';
- $output .= sprintf(
- wp_kses( /* translators: %s - total amount of choices. */
- __( 'Showing the first 20 choices.<br> All %s choices will be displayed when viewing the form.', 'wpforms-lite' ),
- [
- 'br' => [],
- ]
- ),
- $total
- );
- $output .= '</div>';
- }
- }
- break;
- }
- if ( ! $echo ) {
- return $output;
- }
- echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- }
- /**
- * Create a new field in the admin AJAX editor.
- *
- * @since 1.0.0
- */
- public function field_new() {
- // Run a security check.
- check_ajax_referer( 'wpforms-builder', 'nonce' );
- // Check for permissions.
- if ( ! wpforms_current_user_can( 'edit_forms' ) ) {
- die( esc_html__( 'You do not have permission.', 'wpforms-lite' ) );
- }
- // Check for form ID.
- if ( ! isset( $_POST['id'] ) || empty( $_POST['id'] ) ) {
- die( esc_html__( 'No form ID found', 'wpforms-lite' ) );
- }
- // Check for field type to add.
- if ( ! isset( $_POST['type'] ) || empty( $_POST['type'] ) ) {
- die( esc_html__( 'No field type found', 'wpforms-lite' ) );
- }
- // Grab field data.
- $field_args = ! empty( $_POST['defaults'] ) && is_array( $_POST['defaults'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['defaults'] ) ) : [];
- $field_type = sanitize_key( $_POST['type'] );
- $field_id = wpforms()->get( 'form' )->next_field_id( absint( $_POST['id'] ) );
- $field = [
- 'id' => $field_id,
- 'type' => $field_type,
- 'label' => $this->name,
- 'description' => '',
- ];
- $field = wp_parse_args( $field_args, $field );
- $field = apply_filters( 'wpforms_field_new_default', $field );
- $field_required = apply_filters( 'wpforms_field_new_required', '', $field );
- $field_class = apply_filters( 'wpforms_field_new_class', '', $field );
- $field_helper_hide = ! empty( $_COOKIE['wpforms_field_helper_hide'] );
- // Field types that default to required.
- if ( ! empty( $field_required ) ) {
- $field_required = 'required';
- $field['required'] = '1';
- }
- // Build Preview.
- ob_start();
- $this->field_preview( $field );
- $prev = ob_get_clean();
- $preview = sprintf(
- '<div class="wpforms-field wpforms-field-%1$s %2$s %3$s" id="wpforms-field-%4$d" data-field-id="%4$d" data-field-type="%5$s">',
- esc_attr( $field_type ),
- esc_attr( $field_required ),
- esc_attr( $field_class ),
- absint( $field['id'] ),
- esc_attr( $field_type )
- );
- if ( apply_filters( 'wpforms_field_new_display_duplicate_button', true, $field ) ) {
- $preview .= sprintf( '<a href="#" class="wpforms-field-duplicate" title="%s"><i class="fa fa-files-o" aria-hidden="true"></i></a>', esc_attr__( 'Duplicate Field', 'wpforms-lite' ) );
- }
- $preview .= sprintf( '<a href="#" class="wpforms-field-delete" title="%s"><i class="fa fa-trash-o"></i></a>', esc_attr__( 'Delete Field', 'wpforms-lite' ) );
- if ( ! $field_helper_hide ) {
- $preview .= sprintf(
- // language=HTML PhpStorm.
- '<div class="wpforms-field-helper">
- <span class="wpforms-field-helper-edit">%s</span>
- <span class="wpforms-field-helper-drag">%s</span>
- <span class="wpforms-field-helper-hide" title="%s">
- <i class="fa fa-times-circle" aria-hidden="true"></i>
- </span>
- </div>',
- esc_html__( 'Click to Edit', 'wpforms-lite' ),
- esc_html__( 'Drag to Reorder', 'wpforms-lite' ),
- esc_html__( 'Hide Helper', 'wpforms-lite' )
- );
- }
- $preview .= $prev;
- $preview .= '</div>';
- // Build Options.
- $class = apply_filters( 'wpforms_builder_field_option_class', '', $field );
- $options = sprintf(
- '<div class="wpforms-field-option wpforms-field-option-%1$s %2$s" id="wpforms-field-option-%3$d" data-field-id="%3$d">',
- sanitize_html_class( $field['type'] ),
- wpforms_sanitize_classes( $class ),
- absint( $field['id'] )
- );
- $options .= sprintf(
- '<input type="hidden" name="fields[%1$d][id]" value="%1$d" class="wpforms-field-option-hidden-id">',
- absint( $field['id'] )
- );
- $options .= sprintf(
- '<input type="hidden" name="fields[%d][type]" value="%s" class="wpforms-field-option-hidden-type">',
- absint( $field['id'] ),
- esc_attr( $field['type'] )
- );
- ob_start();
- $this->field_options( $field );
- $options .= ob_get_clean();
- $options .= '</div>';
- // Prepare to return compiled results.
- wp_send_json_success(
- [
- 'form_id' => absint( $_POST['id'] ),
- 'field' => $field,
- 'preview' => $preview,
- 'options' => $options,
- ]
- );
- }
- /**
- * Display the field input elements on the frontend.
- *
- * @since 1.0.0
- * @since 1.5.0 Converted to abstract method, as it's required for all fields.
- *
- * @param array $field Field data and settings.
- * @param array $field_atts Field attributes.
- * @param array $form_data Form data and settings.
- */
- abstract public function field_display( $field, $field_atts, $form_data );
- /**
- * Display field input errors if present.
- *
- * @since 1.3.7
- *
- * @param string $key Input key.
- * @param array $field Field data and settings.
- */
- public function field_display_error( $key, $field ) {
- // Need an error.
- if ( empty( $field['properties']['error']['value'][ $key ] ) ) {
- return;
- }
- printf(
- '<label class="wpforms-error" for="%s">%s</label>',
- esc_attr( $field['properties']['inputs'][ $key ]['id'] ),
- esc_html( $field['properties']['error']['value'][ $key ] )
- );
- }
- /**
- * Display field input sublabel if present.
- *
- * @since 1.3.7
- *
- * @param string $key Input key.
- * @param string $position Sublabel position.
- * @param array $field Field data and settings.
- */
- public function field_display_sublabel( $key, $position, $field ) {
- // Need a sublabel value.
- if ( empty( $field['properties']['inputs'][ $key ]['sublabel']['value'] ) ) {
- return;
- }
- $pos = ! empty( $field['properties']['inputs'][ $key ]['sublabel']['position'] ) ? $field['properties']['inputs'][ $key ]['sublabel']['position'] : 'after';
- $hidden = ! empty( $field['properties']['inputs'][ $key ]['sublabel']['hidden'] ) ? 'wpforms-sublabel-hide' : '';
- if ( $pos !== $position ) {
- return;
- }
- printf(
- '<label for="%s" class="wpforms-field-sublabel %s %s">%s</label>',
- esc_attr( $field['properties']['inputs'][ $key ]['id'] ),
- sanitize_html_class( $pos ),
- $hidden,
- $field['properties']['inputs'][ $key ]['sublabel']['value']
- );
- }
- /**
- * Validate field on form submit.
- *
- * @since 1.0.0
- *
- * @param int $field_id Field ID.
- * @param mixed $field_submit Field value that was submitted.
- * @param array $form_data Form data and settings.
- */
- public function validate( $field_id, $field_submit, $form_data ) {
- // Basic required check - If field is marked as required, check for entry data.
- if ( ! empty( $form_data['fields'][ $field_id ]['required'] ) && empty( $field_submit ) && '0' !== (string) $field_submit ) {
- wpforms()->process->errors[ $form_data['id'] ][ $field_id ] = wpforms_get_required_label();
- }
- }
- /**
- * Format and sanitize field.
- *
- * @since 1.0.0
- *
- * @param int $field_id Field ID.
- * @param mixed $field_submit Field value that was submitted.
- * @param array $form_data Form data and settings.
- */
- public function format( $field_id, $field_submit, $form_data ) {
- if ( is_array( $field_submit ) ) {
- $field_submit = array_filter( $field_submit );
- $field_submit = implode( "\r\n", $field_submit );
- }
- $name = ! empty( $form_data['fields'][ $field_id ]['label'] ) ? sanitize_text_field( $form_data['fields'][ $field_id ]['label'] ) : '';
- // Sanitize but keep line breaks.
- $value = wpforms_sanitize_textarea_field( $field_submit );
- wpforms()->process->fields[ $field_id ] = array(
- 'name' => $name,
- 'value' => $value,
- 'id' => absint( $field_id ),
- 'type' => $this->type,
- );
- }
- /**
- * Get field name for ajax error message.
- *
- * @since 1.6.3
- *
- * @param string $name Field name for error triggered.
- * @param array $field Field settings.
- * @param array $props List of properties.
- * @param string $error Error message.
- *
- * @return string
- */
- public function ajax_error_field_name( $name, $field, $props, $error ) {
- if ( $name ) {
- return $name;
- }
- $input = isset( $props['inputs']['primary'] ) ? $props['inputs']['primary'] : end( $props['inputs'] );
- return (string) isset( $input['attr']['name'] ) ? $input['attr']['name'] : '';
- }
- /**
- * Enqueue Choicesjs script and config.
- *
- * @param array $forms Forms on the current page.
- *
- * @since 1.6.3
- */
- protected function enqueue_choicesjs_once( $forms ) {
- if ( wpforms()->frontend->is_choicesjs_enqueued ) {
- return;
- }
- wp_enqueue_script(
- 'wpforms-choicesjs',
- WPFORMS_PLUGIN_URL . 'assets/js/choices.min.js',
- array(),
- '9.0.1',
- true
- );
- $config = [
- 'removeItemButton' => true,
- 'shouldSort' => false,
- 'loadingText' => esc_html__( 'Loading...', 'wpforms-lite' ),
- 'noResultsText' => esc_html__( 'No results found.', 'wpforms-lite' ),
- 'noChoicesText' => esc_html__( 'No choices to choose from.', 'wpforms-lite' ),
- 'itemSelectText' => esc_attr__( 'Press to select.', 'wpforms-lite' ),
- 'uniqueItemText' => esc_html__( 'Only unique values can be added.', 'wpforms-lite' ),
- 'customAddItemText' => esc_html__( 'Only values matching specific conditions can be added.', 'wpforms-lite' ),
- ];
- // Allow theme/plugin developers to modify the provided or add own Choices.js settings.
- $config = apply_filters( 'wpforms_field_select_choicesjs_config', $config, $forms, $this );
- wp_localize_script(
- 'wpforms-choicesjs',
- 'wpforms_choicesjs_config',
- $config
- );
- wpforms()->frontend->is_choicesjs_enqueued = true;
- }
- /**
- * Whether a Choicesjs search area should be shown.
- *
- * @since 1.6.4
- *
- * @param int $choices_count Choices amount.
- *
- * @return bool
- */
- protected function is_choicesjs_search_enabled( $choices_count ) {
- // We should auto hide/remove search, if less than 8 choices.
- return $choices_count >= (int) apply_filters( 'wpforms_field_choicesjs_search_enabled_items_min', 8 );
- }
- }
|