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

Yoast / wordpress-seo / dd6e866a9e6d253114633104d9e3858d807178ba

19 Jun 2024 10:03AM UTC coverage: 48.628% (-4.3%) from 52.936%
dd6e866a9e6d253114633104d9e3858d807178ba

push

github

web-flow
Merge pull request #21431 from Yoast/21429-update-copy-in-the-introduction-and-consent-modals

Updates the copy for the introduction and consent modals

7441 of 13454 branches covered (55.31%)

Branch coverage included in aggregate %.

0 of 3 new or added lines in 2 files covered. (0.0%)

3718 existing lines in 107 files now uncovered.

25100 of 53464 relevant lines covered (46.95%)

62392.47 hits per line

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

98.44
/src/integrations/watchers/indexable-ancestor-watcher.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations\Watchers;
4

5
use Yoast\WP\SEO\Builders\Indexable_Hierarchy_Builder;
6
use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
7
use Yoast\WP\SEO\Helpers\Indexable_Helper;
8
use Yoast\WP\SEO\Helpers\Permalink_Helper;
9
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
10
use Yoast\WP\SEO\Integrations\Integration_Interface;
11
use Yoast\WP\SEO\Models\Indexable;
12
use Yoast\WP\SEO\Repositories\Indexable_Hierarchy_Repository;
13
use Yoast\WP\SEO\Repositories\Indexable_Repository;
14

15
/**
16
 * Ancestor watcher to update the ancestor's children.
17
 *
18
 * Updates its children's permalink when the ancestor itself is updated.
19
 */
20
class Indexable_Ancestor_Watcher implements Integration_Interface {
21

22
        /**
23
         * Represents the indexable repository.
24
         *
25
         * @var Indexable_Repository
26
         */
27
        protected $indexable_repository;
28

29
        /**
30
         * Represents the indexable hierarchy builder.
31
         *
32
         * @var Indexable_Hierarchy_Builder
33
         */
34
        protected $indexable_hierarchy_builder;
35

36
        /**
37
         * Represents the indexable hierarchy repository.
38
         *
39
         * @var Indexable_Hierarchy_Repository
40
         */
41
        protected $indexable_hierarchy_repository;
42

43
        /**
44
         * The indexable helper.
45
         *
46
         * @var Indexable_Helper
47
         */
48
        private $indexable_helper;
49

50
        /**
51
         * Represents the permalink helper.
52
         *
53
         * @var Permalink_Helper
54
         */
55
        protected $permalink_helper;
56

57
        /**
58
         * The post type helper.
59
         *
60
         * @var Post_Type_Helper
61
         */
62
        protected $post_type_helper;
63

64
        /**
65
         * Sets the needed dependencies.
66
         *
67
         * @param Indexable_Repository           $indexable_repository           The indexable repository.
68
         * @param Indexable_Hierarchy_Builder    $indexable_hierarchy_builder    The indexable hierarchy builder.
69
         * @param Indexable_Hierarchy_Repository $indexable_hierarchy_repository The indexable hierarchy repository.
70
         * @param Indexable_Helper               $indexable_helper               The indexable helper.
71
         * @param Permalink_Helper               $permalink_helper               The permalink helper.
72
         * @param Post_Type_Helper               $post_type_helper               The post type helper.
73
         */
74
        public function __construct(
2✔
75
                Indexable_Repository $indexable_repository,
76
                Indexable_Hierarchy_Builder $indexable_hierarchy_builder,
77
                Indexable_Hierarchy_Repository $indexable_hierarchy_repository,
78
                Indexable_Helper $indexable_helper,
79
                Permalink_Helper $permalink_helper,
80
                Post_Type_Helper $post_type_helper
81
        ) {
1✔
82
                $this->indexable_repository           = $indexable_repository;
2✔
83
                $this->indexable_hierarchy_builder    = $indexable_hierarchy_builder;
2✔
84
                $this->indexable_hierarchy_repository = $indexable_hierarchy_repository;
2✔
85
                $this->indexable_helper               = $indexable_helper;
2✔
86
                $this->permalink_helper               = $permalink_helper;
2✔
87
                $this->post_type_helper               = $post_type_helper;
2✔
88
        }
1✔
89

90
        /**
91
         * Registers the appropriate hooks.
92
         *
93
         * @return void
94
         */
95
        public function register_hooks() {
2✔
96
                \add_action( 'wpseo_save_indexable', [ $this, 'reset_children' ], \PHP_INT_MAX, 2 );
2✔
97
        }
1✔
98

99
        /**
100
         * Returns the conditionals based on which this loadable should be active.
101
         *
102
         * @return array<Migrations_Conditional>
103
         */
104
        public static function get_conditionals() {
2✔
105
                return [ Migrations_Conditional::class ];
2✔
106
        }
107

108
        /**
109
         * If an indexable's permalink has changed, updates its children in the hierarchy table and resets the children's permalink.
110
         *
111
         * @param Indexable $indexable        The indexable.
112
         * @param Indexable $indexable_before The old indexable.
113
         *
114
         * @return bool True if the children were reset.
115
         */
116
        public function reset_children( $indexable, $indexable_before ) {
8✔
117
                if ( ! \in_array( $indexable->object_type, [ 'post', 'term' ], true ) ) {
8✔
118
                        return false;
2✔
119
                }
120

121
                // If the permalink was null it means it was reset instead of changed.
122
                if ( $indexable->permalink === $indexable_before->permalink || \is_null( $indexable_before->permalink ) ) {
6✔
123
                        return false;
2✔
124
                }
125

126
                $child_indexable_ids = $this->indexable_hierarchy_repository->find_children( $indexable );
4✔
127
                $child_indexables    = $this->indexable_repository->find_by_ids( $child_indexable_ids );
4✔
128

129
                \array_walk( $child_indexables, [ $this, 'update_hierarchy_and_permalink' ] );
4✔
130
                if ( $indexable->object_type === 'term' ) {
4✔
131
                        $child_indexables_for_term = $this->get_children_for_term( $indexable->object_id, $child_indexables );
2✔
132

133
                        \array_walk( $child_indexables_for_term, [ $this, 'update_hierarchy_and_permalink' ] );
2✔
134
                }
135

136
                return true;
4✔
137
        }
138

139
        /**
140
         * Finds all child indexables for the given term.
141
         *
142
         * @param int              $term_id          Term to fetch the indexable for.
143
         * @param array<Indexable> $child_indexables The already known child indexables.
144
         *
145
         * @return array<Indexable> The list of additional child indexables for a given term.
146
         */
147
        public function get_children_for_term( $term_id, array $child_indexables ) {
2✔
148
                // Finds object_ids (posts) for the term.
149
                $post_object_ids = $this->get_object_ids_for_term( $term_id, $child_indexables );
2✔
150

151
                // Removes the objects that are already present in the children.
152
                $existing_post_indexables = \array_filter(
2✔
153
                        $child_indexables,
2✔
154
                        static function ( $indexable ) {
1✔
155
                                return $indexable->object_type === 'post';
2✔
156
                        }
1✔
157
                );
1✔
158

159
                $existing_post_object_ids = \wp_list_pluck( $existing_post_indexables, 'object_id' );
2✔
160
                $post_object_ids          = \array_diff( $post_object_ids, $existing_post_object_ids );
161

162
                // Finds the indexables for the fetched post_object_ids.
163
                $post_indexables = $this->indexable_repository->find_by_multiple_ids_and_type( $post_object_ids, 'post', false );
164

165
                // Finds the indexables for the posts that are attached to the term.
166
                $post_indexable_ids       = \wp_list_pluck( $post_indexables, 'id' );
2✔
167
                $additional_indexable_ids = $this->indexable_hierarchy_repository->find_children_by_ancestor_ids( $post_indexable_ids );
168

169
                // Makes sure we only have indexable id's that we haven't fetched before.
170
                $additional_indexable_ids = \array_diff( $additional_indexable_ids, $post_indexable_ids );
171

172
                // Finds the additional indexables.
173
                $additional_indexables = $this->indexable_repository->find_by_ids( $additional_indexable_ids );
174

175
                // Merges all fetched indexables.
176
                return \array_merge( $post_indexables, $additional_indexables );
177
        }
178

179
        /**
180
         * Updates the indexable hierarchy and indexable permalink.
181
         *
182
         * @param Indexable $indexable The indexable to update the hierarchy and permalink for.
183
         *
184
         * @return void
185
         */
186
        protected function update_hierarchy_and_permalink( $indexable ) {
4✔
187
                if ( \is_a( $indexable, Indexable::class ) ) {
4✔
188
                        $this->indexable_hierarchy_builder->build( $indexable );
189

190
                        $indexable->permalink = $this->permalink_helper->get_permalink_for_indexable( $indexable );
4✔
191
                        $this->indexable_helper->save_indexable( $indexable );
192
                }
2✔
193
        }
194

195
        /**
196
         * Retrieves the object id's for a term based on the term-post relationship.
197
         *
198
         * @param int              $term_id          The term to get the object id's for.
199
         * @param array<Indexable> $child_indexables The child indexables.
200
         *
201
         * @return array<int> List with object ids for the term.
202
         */
203
        protected function get_object_ids_for_term( $term_id, $child_indexables ) {
2✔
204
                global $wpdb;
205

206
                $filter_terms = static function ( $child ) {
1✔
207
                        return $child->object_type === 'term';
1✔
208
                };
1✔
209

210
                $child_terms      = \array_filter( $child_indexables, $filter_terms );
2✔
211
                $child_object_ids = \array_merge( [ $term_id ], \wp_list_pluck( $child_terms, 'object_id' ) );
212

213
                // Get the term-taxonomy id's for the term and its children.
214
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
215
                $term_taxonomy_ids = $wpdb->get_col(
2✔
216
                        $wpdb->prepare(
1✔
217
                                'SELECT term_taxonomy_id
1✔
218
                                FROM %i
1✔
219
                                WHERE term_id IN( ' . \implode( ', ', \array_fill( 0, ( \count( $child_object_ids ) ), '%s' ) ) . ' )',
2✔
220
                                $wpdb->term_taxonomy,
2✔
221
                                ...$child_object_ids
1✔
222
                        )
1✔
223
                );
1✔
224

225
                // In the case of faulty data having been saved the above query can return 0 results.
UNCOV
226
                if ( empty( $term_taxonomy_ids ) ) {
×
227
                        return [];
228
                }
229

230
                // Get the (post) object id's that are attached to the term.
231
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
232
                return $wpdb->get_col(
2✔
233
                        $wpdb->prepare(
1✔
234
                                'SELECT DISTINCT object_id
1✔
235
                                FROM %i
1✔
236
                                WHERE term_taxonomy_id IN( ' . \implode( ', ', \array_fill( 0, \count( $term_taxonomy_ids ), '%s' ) ) . ' )',
2✔
237
                                $wpdb->term_relationships,
2✔
238
                                ...$term_taxonomy_ids
1✔
239
                        )
1✔
240
                );
1✔
241
        }
242
}
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

© 2025 Coveralls, Inc