|null $layout Defaults to FormLayout::current().
*/
public static function fields( ?array $layout = null ): string {
$out = '';
foreach ( $layout ?? FormLayout::current() as $entry ) {
if ( FormLayout::HIDDEN !== $entry['answer'] ) {
$out .= self::field( $entry );
}
}
return '
' . $out . '
';
}
/**
* The guest's part of the form, split the way the booking flow asks it
* once a time is picked (the date, guests and time are asked before):
*
* - `contact`: the name, phone and email, and the owner's required fields
* - `more`: the other optional fields, each folded under its label
* - `consent`: the owner's checkboxes, such as "Send me offers by email"
*
* @param list|null $layout Defaults to FormLayout::current().
* @return array{contact:string,more:string,consent:string}
*/
public static function flow( ?array $layout = null ): array {
$out = [
'contact' => '',
'more' => '',
'consent' => '',
];
foreach ( $layout ?? FormLayout::current() as $entry ) {
if ( FormLayout::HIDDEN === $entry['answer'] || ( ! $entry['custom'] && in_array( $entry['id'], [ 'date', 'party_size', 'time' ], true ) ) ) {
continue;
}
if ( $entry['custom'] && 'checkbox' === $entry['type'] ) {
$out['consent'] .= self::field( $entry );
} elseif ( FormLayout::REQUIRED === $entry['answer'] || ( ! $entry['custom'] && 'notes' !== $entry['id'] ) ) {
$out['contact'] .= self::field( $entry );
} else {
$out['more'] .= sprintf(
'%1$s
%2$s
',
esc_html( FormLayout::label( $entry ) ),
self::field( array_merge( $entry, [ 'width' => 'full' ] ) )
);
}
}
foreach ( [ 'contact', 'consent' ] as $part ) {
if ( '' !== $out[ $part ] ) {
$out[ $part ] = '' . $out[ $part ] . '
';
}
}
return $out;
}
/**
* The tags and attributes the fields are built from, for wp_kses() where
* the form prints them.
*
* @return array>
*/
public static function allowed_html(): array {
$common = [
'class' => true,
'id' => true,
'hidden' => true,
'aria-describedby' => true,
];
$input = $common + [
'type' => true,
'name' => true,
'value' => true,
'min' => true,
'max' => true,
'step' => true,
'maxlength' => true,
'inputmode' => true,
'autocomplete' => true,
'placeholder' => true,
'required' => true,
'disabled' => true,
'data-fxtr-date' => true,
'data-disabled-weekdays' => true,
'data-disabled-dates' => true,
];
return [
'div' => $common,
'p' => $common,
'span' => $common,
'label' => $common,
'fieldset' => $common,
'legend' => $common,
'details' => $common,
'summary' => $common,
'input' => $input,
'textarea' => $input + [ 'rows' => true ],
'select' => $input,
'option' => [
'value' => true,
'selected' => true,
],
];
}
/**
* @param Entry $entry
*/
private static function field( array $entry ): string {
$required = FormLayout::REQUIRED === $entry['answer'];
$label = esc_html( FormLayout::label( $entry ) ) . ( $required ? ' *' : '' );
$help = '';
$describe = '';
if ( '' !== $entry['help'] ) {
$id = 'fxtr-help-' . ( ++self::$help );
$help = sprintf( '%s', esc_attr( $id ), esc_html( $entry['help'] ) );
$describe = sprintf( ' aria-describedby="%s"', esc_attr( $id ) );
}
$row = 'fxtr-booking-form__row' . ( 'half' === $entry['width'] ? ' fxtr-booking-form__row--half' : '' );
if ( 'radio' === $entry['type'] ) {
return sprintf( '', esc_attr( $row ), $label, self::radios( $entry, $required, $describe ), $help );
}
if ( 'checkbox' === $entry['type'] ) {
return sprintf(
'%6$s
',
esc_attr( $row ),
esc_attr( self::name( $entry ) ),
$required ? ' required' : '',
$describe,
$label,
$help
);
}
return sprintf( '', esc_attr( $row ), $label, self::control( $entry, $required, $describe ), $help );
}
/**
* @param Entry $entry
*/
private static function control( array $entry, bool $required, string $describe ): string {
$name = esc_attr( self::name( $entry ) );
$req = $required ? ' required' : '';
$extra = $req . $describe . ( '' !== $entry['placeholder'] ? sprintf( ' placeholder="%s"', esc_attr( $entry['placeholder'] ) ) : '' );
switch ( $entry['custom'] ? 'custom-' . $entry['type'] : $entry['id'] ) {
case 'date':
return sprintf(
'',
esc_attr( current_time( 'Y-m-d' ) ),
BlockRegistry::closed_day_attributes(),
$describe
);
case 'party_size':
return sprintf( '', (int) Policy::party_max(), $describe );
case 'time':
return sprintf( '', $describe, esc_html__( 'Pick a date first', 'flexatech-table-reservations' ) );
case 'customer_name':
return sprintf( '', $extra );
case 'phone':
return sprintf( '', $extra );
case 'email':
return sprintf( '', $extra );
case 'notes':
return sprintf( '', $extra );
case 'custom-textarea':
return sprintf( '', $name, $extra );
case 'custom-select':
$options = sprintf( '', esc_html( '' !== $entry['placeholder'] ? $entry['placeholder'] : __( 'Choose…', 'flexatech-table-reservations' ) ) );
foreach ( $entry['options'] as $choice ) {
$options .= sprintf( '', esc_attr( $choice['value'] ), esc_html( $choice['label'] ) );
}
return sprintf( '', $name, $req, $describe, $options );
case 'custom-date':
return sprintf( '', $name, $req, $describe );
case 'custom-number':
return sprintf( '', $name, $extra );
case 'custom-email':
return sprintf( '', $name, $extra );
case 'custom-tel':
return sprintf( '', $name, $extra );
default:
return sprintf( '', $name, $extra );
}
}
/**
* @param Entry $entry
*/
private static function radios( array $entry, bool $required, string $describe ): string {
$out = '';
foreach ( $entry['options'] as $i => $choice ) {
$out .= sprintf(
'',
esc_attr( self::name( $entry ) ),
esc_attr( $choice['value'] ),
$required && 0 === $i ? ' required' : '',
0 === $i ? $describe : '',
esc_html( $choice['label'] )
);
}
return $out;
}
/**
* @param Entry $entry
*/
private static function name( array $entry ): string {
return $entry['custom'] ? 'fields[' . $entry['id'] . ']' : $entry['id'];
}
}