@@ -1033,11 +1033,47 @@ private static function parse_subclass_selector( string $input, int &$offset ) {
10331033 */
10341034final class WP_CSS_Complex_Selector extends WP_CSS_Selector_Parser {
10351035 public function matches ( WP_HTML_Processor $ processor ): bool {
1036- // @todo this can throw on parse.
1037- if ( count ( $ this ->selectors ) > 1 ) {
1038- throw new Exception ( 'Combined complex selectors are not supported yet. ' );
1036+ if ( count ( $ this ->selectors ) === 1 ) {
1037+ return $ this ->selectors [0 ]->matches ( $ processor );
1038+ }
1039+
1040+ // First selector must match this location.
1041+ if ( ! $ this ->selectors [0 ]->matches ( $ processor ) ) {
1042+ return false ;
1043+ }
1044+
1045+ $ breadcrumbs = array_slice ( array_reverse ( $ processor ->get_breadcrumbs () ), 1 );
1046+ $ selectors = array_slice ( $ this ->selectors , 1 );
1047+ return $ this ->explore_matches ( $ selectors , $ breadcrumbs );
1048+ }
1049+
1050+ /**
1051+ * This only looks at breadcrumbs and can therefore only support type selectors.
1052+ *
1053+ * @param array<WP_CSS_Selector> $selectors
1054+ */
1055+ private function explore_matches ( array $ selectors , array $ breadcrumbs ): bool {
1056+ if ( array () === $ selectors ) {
1057+ return true ;
1058+ }
1059+ if ( array () === $ breadcrumbs ) {
1060+ return false ;
1061+ }
1062+
1063+ $ combinator = $ selectors [0 ];
1064+ $ selector = $ selectors [1 ];
1065+
1066+ switch ( $ combinator ) {
1067+ case self ::COMBINATOR_CHILD :
1068+ if ( '* ' === $ selector ->type_selector ->ident || strcasecmp ( $ breadcrumbs [0 ], $ selector ->type_selector ->ident ) === 0 ) {
1069+ return $ this ->explore_matches ( array_slice ( $ selectors , 2 ), array_slice ( $ breadcrumbs , 1 ) );
1070+ }
1071+ return $ this ->explore_matches ( $ selectors , array_slice ( $ breadcrumbs , 1 ) );
1072+
1073+ case self ::COMBINATOR_DESCENDANT :
1074+ default :
1075+ throw new Exception ( "Combinator ' {$ combinator }' is not supported yet. " );
10391076 }
1040- return $ this ->selectors [0 ]->matches ( $ processor );
10411077 }
10421078
10431079 const COMBINATOR_CHILD = '> ' ;
@@ -1047,12 +1083,15 @@ public function matches( WP_HTML_Processor $processor ): bool {
10471083
10481084 /**
10491085 * even indexes are WP_CSS_Selector, odd indexes are string combinators.
1086+ * In reverse order to match the current element and then work up the tree.
1087+ * Any non-final selector is a type selector.
1088+ *
10501089 * @var array<WP_CSS_Selector>
10511090 */
10521091 public $ selectors = array ();
10531092
10541093 private function __construct ( array $ selectors ) {
1055- $ this ->selectors = $ selectors ;
1094+ $ this ->selectors = array_reverse ( $ selectors ) ;
10561095 }
10571096
10581097 public static function parse ( string $ input , int &$ offset ): ?self {
0 commit comments