)#is', $html, -1, PREG_SPLIT_DELIM_CAPTURE ); if ( false === $parts ) { return $html; } $drawn = false; $ids = array(); foreach ( $parts as $i => $part ) { if ( 1 === $i % 2 || ! str_contains( $part, ']*>.*?#is', static function ( array $m ) use ( &$drawn, &$ids ): string { $out = self::shell( $m[0] ); if ( $out !== $m[0] ) { $drawn = true; if ( 1 === preg_match( '#^]*\sid="([^"]+)"#i', $m[0], $id ) ) { $ids[] = $id[1]; } } return $out; }, $part ); } if ( $drawn ) { Assets::enqueue_combo_style(); } if ( array() !== $ids ) { $names = implode( '|', array_map( static fn( string $id ): string => preg_quote( $id, '#' ), $ids ) ); foreach ( $parts as $i => $part ) { if ( 0 === $i % 2 && str_contains( $part, ']*\sfor=")(' . $names . ')(")#i', '$1$2-combo$3', $part ); } } } return implode( '', $parts ); } public static function shell( string $select ): string { $tags = new \WP_HTML_Tag_Processor( $select ); if ( ! $tags->next_tag( 'SELECT' ) ) { return $select; } foreach ( array( 'data-rl-native', 'data-rl-combo', 'data-rl-shell' ) as $skip ) { if ( null !== $tags->get_attribute( $skip ) ) { return $select; } } $multi = null !== $tags->get_attribute( 'multiple' ); $summary = $multi && null !== $tags->get_attribute( 'data-rl-summary' ); $remote = '' !== (string) $tags->get_attribute( 'data-rl-search' ); $disabled = null !== $tags->get_attribute( 'disabled' ); $id = (string) $tags->get_attribute( 'id' ); $copy = array(); foreach ( array( 'aria-label', 'aria-labelledby', 'aria-describedby' ) as $name ) { $value = $tags->get_attribute( $name ); if ( is_string( $value ) ) { $copy[ $name ] = $value; } } $required = null !== $tags->get_attribute( 'required' ); $placeholder = (string) $tags->get_attribute( 'data-placeholder' ); $l10n = Assets::select_l10n(); if ( '' === $placeholder ) { $placeholder = $remote ? $l10n['search'] : $l10n['choose']; } $add = array( 'class' => 'rooster-lms-combo__native', 'tabindex' => '-1', 'aria-hidden' => 'true', 'data-rl-ready' => '1', 'data-rl-shell' => '1', ); $end = ''; foreach ( $add as $name => $value ) { if ( null === $tags->get_attribute( $name ) ) { $end .= ' ' . $name . '="' . esc_attr( $value ) . '"'; } elseif ( 'class' === $name ) { $tags->add_class( $value ); } else { $tags->set_attribute( $name, $value ); } } $native = $tags->get_updated_html(); $close = (int) strpos( $native, '>' ); $native = substr( $native, 0, $close ) . $end . substr( $native, $close ); $items = self::items( $select, $multi ); $chosen = array_values( array_filter( $items, static fn( array $i ): bool => $i['selected'] && ( ( $multi && ! $summary ) || '' !== $i['value'] ) ) ); $value = ''; $chips = ''; $clear = true; if ( $summary ) { $value = self::summary( $items, $chosen, $l10n ); } elseif ( $multi ) { foreach ( $chosen as $item ) { $remove = str_replace( '%s', $item['label'], $l10n['remove'] ); $chips .= '' . esc_html( $item['label'] ) . '' . ''; } $placeholder = array() !== $chosen ? '' : $placeholder; $clear = array() === $chosen || $disabled; } else { foreach ( $items as $item ) { if ( $item['selected'] ) { $value = $item['label']; break; } } } $kind = $summary ? ' is-single is-summary' : ( $multi ? ' is-multi' : ' is-single' ); $input = ' $attr ) { $input .= ' ' . $name . '="' . esc_attr( $attr ) . '"'; } $input .= ( $required ? ' aria-required="true"' : '' ) . ( $disabled ? ' disabled' : '' ) . ' value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $placeholder ) . '">'; return $native . '' . ( $multi && ! $summary ? '' . $chips . '' : '' ) . $input . '' . ''; } public static function items( string $select, bool $multi ): array { $tags = new \WP_HTML_Tag_Processor( $select ); $options = array(); $open = -1; while ( $tags->next_token() ) { $token = $tags->get_token_name(); if ( 'OPTION' === $token || 'OPTGROUP' === $token || 'SELECT' === $token ) { $open = -1; if ( 'OPTION' === $token && ! $tags->is_tag_closer() ) { $value = $tags->get_attribute( 'value' ); $options[] = array( 'value' => is_string( $value ) ? $value : null, 'text' => '', 'selected' => null !== $tags->get_attribute( 'selected' ), 'disabled' => null !== $tags->get_attribute( 'disabled' ), 'hidden' => null !== $tags->get_attribute( 'hidden' ), ); $open = count( $options ) - 1; } continue; } if ( $open >= 0 && '#text' === $token ) { $options[ $open ]['text'] .= $tags->get_modifiable_text(); } } if ( ! $multi ) { $pick = -1; foreach ( $options as $i => $option ) { if ( $option['selected'] ) { $pick = $i; } } if ( $pick < 0 ) { foreach ( $options as $i => $option ) { if ( ! $option['disabled'] ) { $pick = $i; break; } } } foreach ( $options as $i => $option ) { $options[ $i ]['selected'] = $i === $pick; } } $out = array(); foreach ( $options as $option ) { if ( $option['hidden'] ) { continue; } $text = $option['text']; $value = $option['value'] ?? trim( (string) preg_replace( '/[\t\n\f\r ]+/', ' ', $text ) ); $label = (string) preg_replace( '/^(?:—\s)+/u', '', $text ); $out[] = array( 'value' => $value, 'label' => (string) preg_replace( '/^\s+|\s+$/u', '', $label ), 'selected' => $option['selected'], ); } return $out; } private static function x_icon( int $size ): string { return ''; } private static function summary( array $items, array $chosen, array $l10n ): string { if ( array() === $chosen ) { foreach ( $items as $item ) { if ( '' === $item['value'] ) { return $item['label']; } } return ''; } if ( count( $chosen ) <= 2 ) { return implode( $l10n['separator'], array_column( $chosen, 'label' ) ); } return str_replace( '%d', (string) count( $chosen ), $l10n['selected'] ); } }