• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / b51d845f89fe206089fb5db4f0ce36d8be6498bf

17 Feb 2026 11:03AM UTC coverage: 53.676%. First build
b51d845f89fe206089fb5db4f0ce36d8be6498bf

push

github

web-flow
Merge pull request #22973 from Yoast/feature/schema_aggregator

Merges `feature/schema-aggregation` to `trunk`

8863 of 16393 branches covered (54.07%)

Branch coverage included in aggregate %.

763 of 1164 new or added lines in 65 files covered. (65.55%)

33819 of 63125 relevant lines covered (53.57%)

47395.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

25.0
/src/schema-aggregator/application/filtering/default-filter.php
1
<?php
2
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
3
namespace Yoast\WP\SEO\Schema_Aggregator\Application\Filtering;
4

5
use Yoast\WP\SEO\Schema_Aggregator\Application\Filtering\Schema_Node_Filter\Schema_Node_Filter_Decider_Interface;
6
use Yoast\WP\SEO\Schema_Aggregator\Application\Filtering\Schema_Node_Property_Filter\Base_Schema_Node_Property_Filter;
7
use Yoast\WP\SEO\Schema_Aggregator\Application\Filtering\Schema_Node_Property_Filter\Schema_Node_Property_Filter_Interface;
8
use Yoast\WP\SEO\Schema_Aggregator\Domain\Schema_Piece;
9
use Yoast\WP\SEO\Schema_Aggregator\Domain\Schema_Piece_Collection;
10
use Yoast\WP\SEO\Schema_Aggregator\Infrastructure\Elements_Context_Map\Elements_Context_Map_Repository_Interface;
11

12
/**
13
 * Default filtering strategy implementation.
14
 */
15
class Default_Filter implements Filtering_Strategy_Interface {
16

17
        private const NODE_FILTER_NAMESPACE     = 'Yoast\WP\SEO\Schema_Aggregator\Application\Filtering\Schema_Node_Filter\\';
18
        private const PROPERTY_FILTER_NAMESPACE = 'Yoast\WP\SEO\Schema_Aggregator\Application\Filtering\Schema_Node_Property_Filter\\';
19
        private const NODE_FILTER_SUFFIX        = '_Schema_Node_Filter';
20
        private const PROPERTY_FILTER_SUFFIX    = '_Schema_Node_Property_Filter';
21

22
        /**
23
         * The categories to filter.
24
         *
25
         * @var array<string>
26
         */
27
        private const FILTER_CATEGORIES = [
28
                'action',
29
                'enumeration',
30
                'meta',
31
                'website-meta',
32
        ];
33

34
        /**
35
         * The elements context map repository.
36
         *
37
         * @var Elements_Context_Map_Repository_Interface
38
         */
39
        private $elements_context_map_repository;
40

41
        /**
42
         * Class constructor.
43
         *
44
         * @param Elements_Context_Map_Repository_Interface $elements_context_map_repository The elements-context map
45
         *                                                                                   repository.
46
         */
47
        public function __construct( Elements_Context_Map_Repository_Interface $elements_context_map_repository ) {
2✔
48
                $this->elements_context_map_repository = $elements_context_map_repository;
2✔
49
        }
50

51
        /**
52
         * Applies filtering to the given schema.
53
         *
54
         * @param Schema_Piece_Collection $schema The schema to be filtered.
55
         *
56
         * @return Schema_Piece_Collection The filtered schema.
57
         */
58
        public function filter( Schema_Piece_Collection $schema ): Schema_Piece_Collection {
38✔
59
                $filtered_schema      = [];
38✔
60
                $elements_context_map = $this->elements_context_map_repository->get_map();
38✔
61

62
                foreach ( $schema->to_array() as $schema_piece ) {
38✔
63
                        $piece_types = (array) $schema_piece->get_type();
36✔
64

65
                        if ( ! $this->should_keep_piece( $piece_types, $elements_context_map, $schema, $schema_piece ) ) {
36✔
66
                                continue;
8✔
67
                        }
68

69
                        $filtered_schema[] = $this->apply_property_filters( $schema_piece, $piece_types );
36✔
70
                }
71

72
                return new Schema_Piece_Collection( $filtered_schema );
38✔
73
        }
74

75
        /**
76
         * Determines if a schema piece should be kept based on all its types.
77
         *
78
         * A piece is kept if at least one of its types should be kept.
79
         *
80
         * @param array<string>                $types                The types to check.
81
         * @param array<string, array<string>> $elements_context_map The elements context map.
82
         * @param Schema_Piece_Collection      $schema               The full schema collection.
83
         * @param Schema_Piece                 $schema_piece         The schema piece being checked.
84
         *
85
         * @return bool Whether to keep the schema piece.
86
         */
NEW
87
        private function should_keep_piece(
×
88
                array $types,
89
                array $elements_context_map,
90
                Schema_Piece_Collection $schema,
91
                Schema_Piece $schema_piece
92
        ): bool {
NEW
93
                foreach ( $types as $type ) {
×
NEW
94
                        if ( $this->should_keep_type( $type, $elements_context_map, $schema, $schema_piece ) ) {
×
NEW
95
                                return true;
×
96
                        }
97
                }
98

NEW
99
                return false;
×
100
        }
101

102
        /**
103
         * Determines if a schema piece should be kept based on a single type.
104
         *
105
         * @param string                       $type                 The type to check.
106
         * @param array<string, array<string>> $elements_context_map The elements context map.
107
         * @param Schema_Piece_Collection      $schema               The full schema collection.
108
         * @param Schema_Piece                 $schema_piece         The schema piece being checked.
109
         *
110
         * @return bool Whether to keep the schema piece.
111
         */
NEW
112
        private function should_keep_type(
×
113
                string $type,
114
                array $elements_context_map,
115
                Schema_Piece_Collection $schema,
116
                Schema_Piece $schema_piece
117
        ): bool {
NEW
118
                foreach ( self::FILTER_CATEGORIES as $category ) {
×
NEW
119
                        if ( ! \in_array( $type, $elements_context_map[ $category ], true ) ) {
×
NEW
120
                                continue;
×
121
                        }
122

NEW
123
                        $filter = $this->get_node_filter( $type );
×
124

NEW
125
                        return ( $filter !== null && $filter->should_filter( $schema, $schema_piece ) );
×
126
                }
127

NEW
128
                return true;
×
129
        }
130

131
        /**
132
         * Gets a node filter instance for the given type.
133
         *
134
         * @param string $type The schema type.
135
         *
136
         * @return Schema_Node_Filter_Decider_Interface|null The filter instance or null if not found.
137
         */
NEW
138
        private function get_node_filter( string $type ): ?Schema_Node_Filter_Decider_Interface {
×
NEW
139
                $filter_class = self::NODE_FILTER_NAMESPACE . $type . self::NODE_FILTER_SUFFIX;
×
140

NEW
141
                if ( \class_exists( $filter_class ) && \is_a( $filter_class, Schema_Node_Filter_Decider_Interface::class, true ) ) {
×
NEW
142
                        return new $filter_class();
×
143
                }
144

NEW
145
                return null;
×
146
        }
147

148
        /**
149
         * Applies property filters for all types of a schema piece.
150
         *
151
         * @param Schema_Piece  $schema_piece The schema piece to filter.
152
         * @param array<string> $types        The types of the schema piece.
153
         *
154
         * @return Schema_Piece The filtered schema piece.
155
         */
NEW
156
        private function apply_property_filters( Schema_Piece $schema_piece, array $types ): Schema_Piece {
×
NEW
157
                $filtered_piece   = $schema_piece;
×
NEW
158
                $filter_was_found = false;
×
159

NEW
160
                foreach ( $types as $type ) {
×
NEW
161
                        $filter = $this->get_property_filter( $type );
×
NEW
162
                        if ( $filter !== null ) {
×
NEW
163
                                $filtered_piece   = $filter->filter_properties( $filtered_piece );
×
NEW
164
                                $filter_was_found = true;
×
165
                        }
166
                }
167

NEW
168
                if ( ! $filter_was_found ) {
×
NEW
169
                        return ( new Base_Schema_Node_Property_Filter() )->filter_properties( $schema_piece );
×
170
                }
171

NEW
172
                return $filtered_piece;
×
173
        }
174

175
        /**
176
         * Gets a property filter instance for the given type.
177
         *
178
         * @param string $type The schema type.
179
         *
180
         * @return Schema_Node_Property_Filter_Interface|null The filter instance or null if not found.
181
         */
NEW
182
        private function get_property_filter( string $type ): ?Schema_Node_Property_Filter_Interface {
×
NEW
183
                $filter_class = self::PROPERTY_FILTER_NAMESPACE . $type . self::PROPERTY_FILTER_SUFFIX;
×
184

NEW
185
                if ( \class_exists( $filter_class ) && \is_a( $filter_class, Schema_Node_Property_Filter_Interface::class, true ) ) {
×
NEW
186
                        return new $filter_class();
×
187
                }
188

NEW
189
                return null;
×
190
        }
191
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc