'system-ui,-apple-system,"Segoe UI",sans-serif', 'serif' => 'Georgia,"Times New Roman",serif', 'system' => 'system-ui,sans-serif', 'mono' => 'ui-monospace,Menlo,monospace' ); $gaps = array( 'compact' => '12px', 'normal' => '18px', 'relaxed' => '26px' ); $style = array(); $class = array(); if ( isset( $d['primary'] ) && preg_match( self::HEX, (string) $d['primary'] ) ) { $style[] = '--htform-accent:' . $d['primary']; } if ( isset( $d['text'] ) && preg_match( self::HEX, (string) $d['text'] ) ) { $style[] = '--htform-ink:' . $d['text']; } if ( isset( $d['background'] ) && preg_match( self::HEX, (string) $d['background'] ) ) { $style[] = '--htform-bg:' . $d['background']; $class[] = 'htform-has-bg'; } if ( isset( $d['radius'] ) && is_numeric( $d['radius'] ) ) { $style[] = '--htform-radius:' . max( 0, min( 24, (int) $d['radius'] ) ) . 'px'; } if ( isset( $d['font'] ) && isset( $fonts[ $d['font'] ] ) ) { $style[] = '--htform-font:' . $fonts[ $d['font'] ]; } if ( isset( $d['spacing'] ) && isset( $gaps[ $d['spacing'] ] ) ) { $style[] = '--htform-gap:' . $gaps[ $d['spacing'] ]; } if ( ! empty( $d['buttonStyle'] ) ) { $class[] = 'htform-btn-' . sanitize_html_class( (string) $d['buttonStyle'] ); } return array( 'style' => implode( ';', $style ), 'class' => implode( ' ', $class ) ); } /** * Full instant markup for the first step of the form. * * @param array $payload Public payload. * @return string */ public static function markup( $payload ) { if ( empty( $payload['schema']['fields'] ) || ! is_array( $payload['schema']['fields'] ) ) { return ''; } $schema = $payload['schema']; $settings = isset( $schema['settings'] ) && is_array( $schema['settings'] ) ? $schema['settings'] : array(); $design = isset( $settings['design'] ) && is_array( $settings['design'] ) ? $settings['design'] : array(); $name = isset( $payload['name'] ) ? (string) $payload['name'] : ''; if ( isset( $payload['schedule'] ) && 'open' !== $payload['schedule'] ) { $closed = ! empty( $settings['closedMessage'] ) ? (string) $settings['closedMessage'] : __( 'This form is not accepting responses right now.', 'htforms-builder' ); return '

' . esc_html( $name ) . '

' . esc_html( $closed ) . '

'; } $conv = isset( $settings['layout'] ) && 'conversational' === $settings['layout']; $first = array(); $steps = 1; $context = array(); $has_question = false; foreach ( $schema['fields'] as $f ) { if ( ! is_array( $f ) || ! isset( $f['type'] ) ) { continue; } if ( 'pagebreak' === $f['type'] ) { if ( ! $conv ) { $steps++; } continue; } if ( $conv ) { if ( 'hidden' === $f['type'] ) { $first[] = $f; continue; } if ( in_array( $f['type'], array( 'html', 'divider', 'image', 'calculation' ), true ) || ! empty( $f['blocksSubmission'] ) ) { if ( ! $has_question ) { $context[] = $f; } continue; } if ( ! $has_question ) { $first = array_merge( $first, $context, array( $f ) ); $has_question = true; } $steps++; continue; } if ( 1 === $steps ) { $first[] = $f; } } if ( $conv ) { $steps = max( 1, $steps - 1 ); } $out = '
'; if ( ! empty( $design['logo'] ) && self::safe_image( (string) $design['logo'] ) ) { $out .= ''; } $out .= '

' . esc_html( $name ) . '

'; if ( ! empty( $settings['description'] ) ) { $out .= '

' . esc_html( (string) $settings['description'] ) . '

'; } $cols = isset( $design['columns'] ) && 2 === (int) $design['columns'] && ! $conv; $out .= '
'; foreach ( $first as $f ) { $out .= self::field( $f ); } $out .= '
'; $btn_style = array(); if ( isset( $settings['submitColor'] ) && preg_match( self::HEX, (string) $settings['submitColor'] ) ) { $btn_style[] = 'background-color:' . $settings['submitColor']; $btn_style[] = 'border-color:' . $settings['submitColor']; } if ( isset( $settings['submitTextColor'] ) && preg_match( self::HEX, (string) $settings['submitTextColor'] ) ) { $btn_style[] = 'color:' . $settings['submitTextColor']; } $btn_style[] = 'font-weight:' . ( isset( $settings['submitBold'] ) && false === $settings['submitBold'] ? '400' : '700' ); $label = $steps > 1 ? __( 'Next', 'htforms-builder' ) : ( ! empty( $settings['submitLabel'] ) ? (string) $settings['submitLabel'] : __( 'Submit', 'htforms-builder' ) ); $align = isset( $settings['submitAlign'] ) ? sanitize_html_class( (string) $settings['submitAlign'] ) : 'left'; $out .= '
'; $out .= '
'; if ( ! empty( $payload['branding'] ) && HTForm_Attribution::enabled() ) { $out .= '

Powered by HTforms

'; } return $out; } /** * Only https or small inline images. * * @param string $src Source. * @return bool */ private static function safe_image( $src ) { return 1 === preg_match( '#^(https://|data:image/(png|jpeg|webp|gif);base64,)#', $src ); } /** * Country list shared with the JS renderer. * * @return string[] */ private static function countries() { static $list = null; if ( null === $list ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- local plugin file. $list = json_decode( (string) file_get_contents( HTFORM_DIR . 'assets/countries.json' ), true ); $list = is_array( $list ) ? $list : array(); } return $list; } /** * One field, same structure and names as htform.js buildField(). * * @param array $f Field. * @return string */ private static function field( $f ) { $type = sanitize_key( (string) $f['type'] ); $fid = isset( $f['id'] ) ? (string) $f['id'] : ''; $id = 'htfs-' . preg_replace( '/[^A-Za-z0-9_-]/', '', $fid ); $lbl = isset( $f['label'] ) ? (string) $f['label'] : ''; $ph = isset( $f['placeholder'] ) ? (string) $f['placeholder'] : ''; $def = isset( $f['defaultValue'] ) && is_scalar( $f['defaultValue'] ) ? (string) $f['defaultValue'] : ''; $req = ! empty( $f['required'] ); $star = $req ? '' : ''; $desc = ! empty( $f['description'] ) ? '

' . esc_html( (string) $f['description'] ) . '

' : ''; $err = ''; $opts = isset( $f['options'] ) && is_array( $f['options'] ) ? array_map( 'strval', $f['options'] ) : array(); if ( 'hidden' === $type ) { return ''; } $cls = 'htform-field htform-type-' . $type; if ( isset( $f['boundaryStyle'] ) && in_array( $f['boundaryStyle'], array( 'sky_dashed', 'orange_solid', 'grey_dashed' ), true ) ) { $cls .= ' htform-bd htform-bd-' . $f['boundaryStyle'] . ' htform-bd-' . sanitize_html_class( isset( $f['boundaryPosition'] ) ? (string) $f['boundaryPosition'] : 'below' ) . ' htform-bda-' . sanitize_html_class( isset( $f['boundaryAnimation'] ) ? (string) $f['boundaryAnimation'] : 'none' ); } $open = '
'; $label = ''; $attrs = ' id="' . esc_attr( $id ) . '" name="' . esc_attr( $fid ) . '"' . ( '' !== $ph ? ' placeholder="' . esc_attr( $ph ) . '"' : '' ) . ( $req ? ' required' : '' ); if ( ! empty( $f['blocksSubmission'] ) ) { return $open . '
'; } switch ( $type ) { case 'calculation': return $open . $label . '0.00' . $desc . ''; case 'repeater': $h = $open . $label . '
'; foreach ( isset( $f['subfields'] ) ? $f['subfields'] : array() as $j => $sub ) { $sl = isset( $sub['label'] ) ? (string) $sub['label'] : ''; $st = isset( $sub['type'] ) ? $sub['type'] : 'text'; $sa = ' name="' . esc_attr( $fid . '__row0__col' . $j ) . '" aria-label="' . esc_attr( $sl ) . '"'; $h .= ''; } return $h . '
' . $desc . $err . ''; case 'signature': return $open . $label . '
' . ( ! empty( $f['signatureDisclaimer'] ) ? '

' . esc_html( $f['signatureDisclaimer'] ) . '

' : '' ) . $desc . $err . ''; case 'likert': $h = $open . $label; foreach ( isset( $f['rows'] ) ? $f['rows'] : array() as $i => $row ) { $h .= '
' . esc_html( $row ) . ''; foreach ( $opts as $v ) $h .= ''; $h .= '
'; } return $h . $desc . $err . ''; case 'rating': case 'nps': $h = $open . $label . '
'; $high = 'nps' === $type ? 10 : ( isset( $f['ratingMax'] ) ? (int) $f['ratingMax'] : 5 ); for ( $n = 'nps' === $type ? 0 : 1; $n <= $high; $n++ ) $h .= ''; return $h . '
' . '

' . esc_html( ( isset( $f['lowLabel'] ) ? $f['lowLabel'] : '' ) . ' — ' . ( isset( $f['highLabel'] ) ? $f['highLabel'] : '' ) ) . '

' . $desc . $err . ''; case 'image': if ( empty( $f['imageUrl'] ) || ! self::safe_image( (string) $f['imageUrl'] ) ) { return $open . ''; } $w = isset( $f['imageWidth'] ) ? max( 10, min( 100, (int) $f['imageWidth'] ) ) : 100; $align = isset( $f['imageAlign'] ) ? (string) $f['imageAlign'] : 'center'; $style = 'width:' . $w . '%;margin-left:' . ( 'left' === $align ? '0' : 'auto' ) . ';margin-right:' . ( 'right' === $align ? '0' : 'auto' ); return $open . '' . esc_attr( $lbl ) . '' . $desc . ''; case 'html': return $open . wp_kses_post( isset( $f['html'] ) ? (string) $f['html'] : '' ) . ''; case 'divider': return $open . '

' . esc_html( $lbl ) . '

' . $desc . ''; case 'name': $format = isset( $f['nameFormat'] ) ? (string) $f['nameFormat'] : 'simple'; if ( 'simple' === $format || '' === $format ) { return $open . $label . '' . $desc . $err . ''; } $middle = 'first_middle_last' === $format; $names = $middle ? array( __( 'First name', 'htforms-builder' ), __( 'Middle name', 'htforms-builder' ), __( 'Last name', 'htforms-builder' ) ) : array( __( 'First name', 'htforms-builder' ), __( 'Last name', 'htforms-builder' ) ); $autos = $middle ? array( 'given-name', 'additional-name', 'family-name' ) : array( 'given-name', 'family-name' ); $parts = '
'; foreach ( $names as $i => $n ) { $pid = 0 === $i ? $id : $id . '-' . $i; $parts .= '
'; } return $open . $label . $parts . '
' . $desc . $err . ''; case 'email': $input = ''; if ( empty( $f['confirmEmail'] ) ) { return $open . $label . $input . $desc . $err . ''; } $cid = $id . '-confirm'; return $open . '
' . $label . $input . '
' . $desc . $err . ''; case 'country': $o = ''; $countries = isset( $f['countryOptions'] ) && is_array( $f['countryOptions'] ) ? $f['countryOptions'] : self::countries(); foreach ( $countries as $c ) { $o .= ''; } return $open . $label . '' . $desc . $err . ''; case 'textarea': case 'address': return $open . $label . '' . $desc . $err . ''; case 'select': $o = ''; foreach ( $opts as $v ) { $o .= ''; } return $open . $label . '' . $o . '' . $desc . $err . ''; case 'multiselect': $o = ''; foreach ( $opts as $v ) { $o .= ''; } return $open . $label . '' . $desc . $err . ''; case 'poll': case 'radio': case 'checkbox': $h = $open . '' . esc_html( $lbl ) . $star . ''; foreach ( $opts as $v ) { $h .= ''; } return $h . $err . ''; case 'consent': return $open . '' . $err . ''; case 'file': return $open . $label . '' . $desc . $err . ''; default: $map = array( 'phone' => 'tel', 'number' => 'number', 'url' => 'url', 'date' => 'date', 'time' => 'time' ); $kind = isset( $map[ $type ] ) ? $map[ $type ] : 'text'; $mm = ( isset( $f['min'] ) && is_numeric( $f['min'] ) ? ' min="' . esc_attr( (string) $f['min'] ) . '"' : '' ) . ( isset( $f['max'] ) && is_numeric( $f['max'] ) ? ' max="' . esc_attr( (string) $f['max'] ) . '"' : '' ); return $open . $label . '' . $desc . $err . ''; } } }