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

Yoast / wordpress-seo / 5025760653

pending completion
5025760653

push

github

aidamarfuaty
Merge branch 'trunk' of github.com:Yoast/wordpress-seo into feature/html-parser

97 of 172 new or added lines in 42 files covered. (56.4%)

9584 of 24000 relevant lines covered (39.93%)

3.32 hits per line

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

15.29
/src/integrations/admin/admin-columns-cache-integration.php
1
<?php
2

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

5
use WP_Post;
6
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
7
use Yoast\WP\SEO\Integrations\Integration_Interface;
8
use Yoast\WP\SEO\Models\Indexable;
9
use Yoast\WP\SEO\Repositories\Indexable_Repository;
10

11
/**
12
 * Admin_Columns_Cache_Integration class.
13
 */
14
class Admin_Columns_Cache_Integration implements Integration_Interface {
15

16
        /**
17
         * Cache of indexables.
18
         *
19
         * @var Indexable[]
20
         */
21
        protected $indexable_cache = [];
22

23
        /**
24
         * The indexable repository.
25
         *
26
         * @var Indexable_Repository
27
         */
28
        protected $indexable_repository;
29

30
        /**
31
         * Returns the conditionals based on which this loadable should be active.
32
         *
33
         * In this case: only when on an admin page.
34
         *
35
         * @return array The conditionals.
36
         */
37
        public static function get_conditionals() {
38
                return [ Admin_Conditional::class ];
×
39
        }
40

41
        /**
42
         * Admin_Columns_Cache_Integration constructor.
43
         *
44
         * @param Indexable_Repository $indexable_repository The indexable repository.
45
         */
46
        public function __construct( Indexable_Repository $indexable_repository ) {
47
                $this->indexable_repository = $indexable_repository;
6✔
48
        }
3✔
49

50
        /**
51
         * Registers the appropriate actions and filters to fill the cache with
52
         * indexables on admin pages.
53
         *
54
         * This cache is used in showing the Yoast SEO columns on the posts overview
55
         * page (e.g. keyword score, incoming link count, etc.)
56
         */
57
        public function register_hooks() {
58
                // Hook into tablenav to calculate links and linked.
59
                \add_action( 'manage_posts_extra_tablenav', [ $this, 'maybe_fill_cache' ] );
×
60
        }
61

62
        /**
63
         * Makes sure we calculate all values in one query by filling our cache beforehand.
64
         *
65
         * @param string $target Extra table navigation location which is triggered.
66
         */
67
        public function maybe_fill_cache( $target ) {
68
                if ( $target === 'top' ) {
×
69
                        $this->fill_cache();
×
70
                }
71
        }
72

73
        /**
74
         * Fills the cache of indexables for all known post IDs.
75
         */
76
        public function fill_cache() {
77
                global $wp_query;
6✔
78

79
                // No need to continue building a cache if the main query did not return anything to cache.
80
                if ( empty( $wp_query->posts ) ) {
6✔
81
                        return;
2✔
82
                }
83

84
                $posts    = $wp_query->posts;
4✔
85
                $post_ids = [];
4✔
86

87
                // Post lists return a list of objects.
88
                if ( isset( $posts[0] ) && \is_a( $posts[0], 'WP_Post' ) ) {
4✔
89
                        $post_ids = \wp_list_pluck( $posts, 'ID' );
4✔
90
                }
91
                elseif ( isset( $posts[0] ) && \is_object( $posts[0] ) ) {
×
92
                        $post_ids = $this->get_current_page_page_ids( $posts );
×
93
                }
94
                elseif ( ! empty( $posts ) ) {
×
95
                        // Page list returns an array of post IDs.
96
                        $post_ids = \array_keys( $posts );
×
97
                }
98

99
                if ( empty( $post_ids ) ) {
4✔
100
                        return;
×
101
                }
102

103
                if ( isset( $posts[0] ) && ! \is_a( $posts[0], WP_Post::class ) ) {
4✔
104
                        // Prime the post caches as core would to avoid duplicate queries.
105
                        // This needs to be done as this executes before core does.
106
                        \_prime_post_caches( $post_ids );
×
107
                }
108

109
                $indexables = $this->indexable_repository->find_by_multiple_ids_and_type( $post_ids, 'post', false );
4✔
110

111
                foreach ( $indexables as $indexable ) {
4✔
112
                        $this->indexable_cache[ $indexable->object_id ] = $indexable;
4✔
113
                }
114
        }
2✔
115

116
        /**
117
         * Returns the indexable for a given post ID.
118
         *
119
         * @param int $post_id The post ID.
120
         *
121
         * @return Indexable|false The indexable. False if none could be found.
122
         */
123
        public function get_indexable( $post_id ) {
124
                if ( ! \array_key_exists( $post_id, $this->indexable_cache ) ) {
×
125
                        $this->indexable_cache[ $post_id ] = $this->indexable_repository->find_by_id_and_type( $post_id, 'post' );
×
126
                }
127
                return $this->indexable_cache[ $post_id ];
×
128
        }
129

130
        /**
131
         * Gets all the page IDs set to be shown on the current page.
132
         * This is copied over with some changes from WP_Posts_List_Table::_display_rows_hierarchical.
133
         *
134
         * @param array $pages The pages, each containing an ID and post_parent.
135
         *
136
         * @return array The IDs of all pages shown on the current page.
137
         */
138
        private function get_current_page_page_ids( $pages ) {
139
                global $per_page;
×
140
                $pagenum = isset( $_REQUEST['paged'] ) ? \absint( $_REQUEST['paged'] ) : 0;
×
141
                $pagenum = \max( 1, $pagenum );
×
142

143
                /*
144
                 * Arrange pages into two parts: top level pages and children_pages
145
                 * children_pages is two dimensional array, eg.
146
                 * children_pages[10][] contains all sub-pages whose parent is 10.
147
                 * It only takes O( N ) to arrange this and it takes O( 1 ) for subsequent lookup operations
148
                 * If searching, ignore hierarchy and treat everything as top level
149
                 */
150
                if ( empty( $_REQUEST['s'] ) ) {
×
151
                        $top_level_pages = [];
×
152
                        $children_pages  = [];
×
153
                        $pages_map       = [];
×
154

155
                        foreach ( $pages as $page ) {
×
156

157
                                // Catch and repair bad pages.
158
                                if ( $page->post_parent === $page->ID ) {
×
159
                                        $page->post_parent = 0;
×
160
                                }
161

162
                                if ( $page->post_parent === 0 ) {
×
163
                                        $top_level_pages[] = $page;
×
164
                                }
165
                                else {
166
                                        $children_pages[ $page->post_parent ][] = $page;
×
167
                                }
168
                                $pages_map[ $page->ID ] = $page;
×
169
                        }
170

NEW
171
                        $pages = $top_level_pages;
×
172
                }
173

174
                $count      = 0;
×
175
                $start      = ( ( $pagenum - 1 ) * $per_page );
×
176
                $end        = ( $start + $per_page );
×
177
                $to_display = [];
×
178

179
                foreach ( $pages as $page ) {
×
180
                        if ( $count >= $end ) {
×
181
                                break;
×
182
                        }
183

184
                        if ( $count >= $start ) {
×
185
                                $to_display[] = $page->ID;
×
186
                        }
187

188
                        ++$count;
×
189

190
                        $this->get_child_page_ids( $children_pages, $count, $page->ID, $start, $end, $to_display, $pages_map );
×
191
                }
192

193
                // If it is the last pagenum and there are orphaned pages, display them with paging as well.
194
                if ( isset( $children_pages ) && $count < $end ) {
×
195
                        foreach ( $children_pages as $orphans ) {
×
196
                                foreach ( $orphans as $op ) {
×
197
                                        if ( $count >= $end ) {
×
198
                                                break;
×
199
                                        }
200

201
                                        if ( $count >= $start ) {
×
202
                                                $to_display[] = $op->ID;
×
203
                                        }
204

205
                                        ++$count;
×
206
                                }
207
                        }
208
                }
209

210
                return $to_display;
×
211
        }
212

213
        /**
214
         * Adds all child pages due to be shown on the current page to the $to_display array.
215
         * Copied over with some changes from WP_Posts_List_Table::_page_rows.
216
         *
217
         * @param array $children_pages The full map of child pages.
218
         * @param int   $count          The number of pages already processed.
219
         * @param int   $parent_id      The id of the parent that's currently being processed.
220
         * @param int   $start          The number at which the current overview starts.
221
         * @param int   $end            The number at which the current overview ends.
222
         * @param int   $to_display     The page IDs to be shown.
223
         * @param int   $pages_map      A map of page ID to an object with ID and post_parent.
224
         *
225
         * @return void
226
         */
227
        private function get_child_page_ids( &$children_pages, &$count, $parent_id, $start, $end, &$to_display, &$pages_map ) {
228
                if ( ! isset( $children_pages[ $parent_id ] ) ) {
×
229
                        return;
×
230
                }
231

232
                foreach ( $children_pages[ $parent_id ] as $page ) {
×
233
                        if ( $count >= $end ) {
×
234
                                break;
×
235
                        }
236

237
                        // If the page starts in a subtree, print the parents.
238
                        if ( $count === $start && $page->post_parent > 0 ) {
×
239
                                $my_parents = [];
×
240
                                $my_parent  = $page->post_parent;
×
241
                                while ( $my_parent ) {
×
242
                                        // Get the ID from the list or the attribute if my_parent is an object.
243
                                        $parent_id = $my_parent;
×
244
                                        if ( \is_object( $my_parent ) ) {
×
245
                                                $parent_id = $my_parent->ID;
×
246
                                        }
247

248
                                        $my_parent    = $pages_map[ $parent_id ];
×
249
                                        $my_parents[] = $my_parent;
×
250
                                        if ( ! $my_parent->post_parent ) {
×
251
                                                break;
×
252
                                        }
253
                                        $my_parent = $my_parent->post_parent;
×
254
                                }
255
                                while ( $my_parent = \array_pop( $my_parents ) ) {
×
256
                                        $to_display[] = $my_parent->ID;
×
257
                                }
258
                        }
259

260
                        if ( $count >= $start ) {
×
261
                                $to_display[] = $page->ID;
×
262
                        }
263

264
                        ++$count;
×
265

266
                        $this->get_child_page_ids( $children_pages, $count, $page->ID, $start, $end, $to_display, $pages_map );
×
267
                }
268

269
                unset( $children_pages[ $parent_id ] ); // Required in order to keep track of orphans.
×
270
        }
271
}
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