'10' ]` or `[ 'custom' => '3.50' ]`. The classic form sends * `[ 'preset' => 'custom', 'custom' => '3,50' ]`, which is normalised the same way. * * @since 1.0.0 */ final class TipType extends AbstractExtraType { public const MAX_PRESETS = 6; /** * {@inheritDoc} */ public function slug(): string { return 'tip'; } /** * {@inheritDoc} */ public function label(): string { return __( 'Tip', 'extrova' ); } /** * {@inheritDoc} */ public function config_schema(): array { return array( 'type' => 'object', 'properties' => array( 'presets' => array( 'type' => 'array', 'maxItems' => self::MAX_PRESETS, 'items' => array( 'type' => array( 'number', 'string' ) ), ), 'allow_custom' => array( 'type' => 'boolean' ), 'min' => array( 'type' => 'string' ), 'max' => array( 'type' => 'string' ), 'base' => array( 'type' => 'string', 'enum' => array( 'subtotal' ), ), ), ); } /** * {@inheritDoc} * * @param array $config Raw config. */ public function sanitize_config( array $config ): array { $presets = array(); foreach ( (array) ( $config['presets'] ?? array( 5, 10, 15 ) ) as $preset ) { $preset = (string) wc_format_decimal( is_scalar( $preset ) ? (string) $preset : '0', 2, true ); if ( (float) $preset > 0 && (float) $preset <= 100 && ! in_array( $preset, $presets, true ) ) { $presets[] = $preset; } } $presets = array_slice( $presets, 0, self::MAX_PRESETS ); $min = max( 0.0, (float) wc_format_decimal( (string) ( $config['min'] ?? '0' ) ) ); $max = max( 0.0, (float) wc_format_decimal( (string) ( $config['max'] ?? '50' ) ) ); if ( $max < $min ) { $max = $min; } return array( 'presets' => $presets, 'allow_custom' => rest_sanitize_boolean( $config['allow_custom'] ?? true ), 'min' => Money::decimal( $min ), 'max' => Money::decimal( $max ), 'base' => 'subtotal', ); } /** * Configured presets as strings. * * @param Extra $extra Extra. * @return string[] */ private function presets( Extra $extra ): array { return array_values( array_map( 'strval', (array) ( $extra->type_config['presets'] ?? array() ) ) ); } /** * {@inheritDoc} * * @param mixed $raw Raw value. * @param Extra $extra Extra. */ public function sanitize_value( mixed $raw, Extra $extra ): mixed { if ( ! is_array( $raw ) ) { return null; } $preset = isset( $raw['preset'] ) && is_scalar( $raw['preset'] ) ? (string) $raw['preset'] : ''; if ( '' !== $preset && 'custom' !== $preset ) { $preset = (string) wc_format_decimal( $preset, 2, true ); return in_array( $preset, $this->presets( $extra ), true ) ? array( 'preset' => $preset ) : null; } if ( ( 'custom' === $preset || array_key_exists( 'custom', $raw ) ) && ! empty( $extra->type_config['allow_custom'] ) ) { $custom = isset( $raw['custom'] ) && is_scalar( $raw['custom'] ) ? (string) $raw['custom'] : ''; if ( '' === trim( $custom ) ) { return null; } $amount = (float) wc_format_decimal( $custom ); $min = (float) ( $extra->type_config['min'] ?? 0 ); $max = (float) ( $extra->type_config['max'] ?? 0 ); $amount = max( $min, min( $max, $amount ) ); return $amount > 0 ? array( 'custom' => Money::decimal( $amount ) ) : null; } return null; } /** * {@inheritDoc} * * @param Extra $extra Extra. * @param Selection $selection Selection. */ public function is_chargeable( Extra $extra, Selection $selection ): bool { return is_array( $selection->value ) && ( isset( $selection->value['preset'] ) || isset( $selection->value['custom'] ) ); } /** * {@inheritDoc} * * Percent presets use the `percent_subtotal` method; custom amounts use `fixed`. * * @param Extra $extra Extra. * @param Selection $selection Selection. */ public function pricing_for( Extra $extra, Selection $selection ): array { $value = is_array( $selection->value ) ? $selection->value : array(); if ( isset( $value['preset'] ) ) { return array( 'method' => 'percent_subtotal', 'percent' => (string) $value['preset'], ); } if ( isset( $value['custom'] ) ) { return array( 'method' => 'fixed', 'amount' => (string) $value['custom'], ); } return array(); } /** * {@inheritDoc} * * @param Extra $extra Extra. * @param Selection $selection Selection. */ public function display_value( Extra $extra, Selection $selection ): string { $value = is_array( $selection->value ) ? $selection->value : array(); if ( isset( $value['preset'] ) ) { return sprintf( /* translators: %s: percentage number. */ __( '%s%%', 'extrova' ), wc_format_localized_decimal( (string) $value['preset'] ) ); } if ( isset( $value['custom'] ) ) { return Money::plain( (string) $value['custom'] ); } return ''; } /** * {@inheritDoc} * * @param Extra $extra Extra. * @param Selection $selection Selection. */ public function fee_name( Extra $extra, Selection $selection ): string { $value = is_array( $selection->value ) ? $selection->value : array(); if ( isset( $value['preset'] ) ) { return sprintf( /* translators: 1: extra label, 2: percentage. */ __( '%1$s (%2$s)', 'extrova' ), $extra->label, $this->display_value( $extra, $selection ) ); } return $extra->label; } /** * {@inheritDoc} * * @param Extra $extra Extra. * @param Context $context Context. */ public function to_client( Extra $extra, Context $context ): array { return array( 'presets' => $this->presets( $extra ), 'allow_custom' => ! empty( $extra->type_config['allow_custom'] ), 'min' => (string) ( $extra->type_config['min'] ?? '0' ), 'max' => (string) ( $extra->type_config['max'] ?? '0' ), ); } /** * {@inheritDoc} * * @param Extra $extra Extra. */ public function preview_selections( Extra $extra ): array { $previews = array(); foreach ( $this->presets( $extra ) as $preset ) { $previews[ $preset ] = array( 'preset' => $preset ); } return $previews; } /** * {@inheritDoc} * * @param Extra $extra Extra. * @param Selection|null $selection Selection. * @param Context $context Context. */ public function render_classic( Extra $extra, ?Selection $selection, Context $context ): string { $value = $selection && is_array( $selection->value ) ? $selection->value : array(); $current = isset( $value['preset'] ) ? (string) $value['preset'] : ( isset( $value['custom'] ) ? 'custom' : '' ); $custom = isset( $value['custom'] ) ? (string) $value['custom'] : ''; $name = $this->field_name( $extra, 'preset' ); $custom_id = $this->field_id( $extra, 'custom-amount' ); $custom_wrap = $this->field_id( $extra, 'custom-wrap' ); $html = '
'; return $html; } }