Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Jetpack_Sitemap_Builder often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Jetpack_Sitemap_Builder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
44 | class Jetpack_Sitemap_Builder { |
||
45 | |||
46 | /** |
||
47 | * Librarian object for storing and retrieving sitemap data. |
||
48 | * |
||
49 | * @access private |
||
50 | * @since 4.8.0 |
||
51 | * @var $librarian Jetpack_Sitemap_Librarian |
||
52 | */ |
||
53 | private $librarian; |
||
54 | |||
55 | /** |
||
56 | * Logger object for reporting debug messages. |
||
57 | * |
||
58 | * @access private |
||
59 | * @since 4.8.0 |
||
60 | * @var $logger Jetpack_Sitemap_Logger |
||
61 | */ |
||
62 | private $logger = false; |
||
63 | |||
64 | /** |
||
65 | * Finder object for dealing with sitemap URIs. |
||
66 | * |
||
67 | * @access private |
||
68 | * @since 4.8.0 |
||
69 | * @var $finder Jetpack_Sitemap_Finder |
||
70 | */ |
||
71 | private $finder; |
||
72 | |||
73 | /** |
||
74 | * Construct a new Jetpack_Sitemap_Builder object. |
||
75 | * |
||
76 | * @access public |
||
77 | * @since 4.8.0 |
||
78 | */ |
||
79 | public function __construct() { |
||
80 | $this->librarian = new Jetpack_Sitemap_Librarian(); |
||
81 | $this->finder = new Jetpack_Sitemap_Finder(); |
||
82 | |||
83 | if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
||
84 | $this->logger = new Jetpack_Sitemap_Logger(); |
||
|
|||
85 | } |
||
86 | |||
87 | update_option( |
||
88 | 'jetpack_sitemap_post_types', |
||
89 | /** |
||
90 | * The array of post types to be included in the sitemap. |
||
91 | * |
||
92 | * Add your custom post type name to the array to have posts of |
||
93 | * that type included in the sitemap. The default array includes |
||
94 | * 'page' and 'post'. |
||
95 | * |
||
96 | * The result of this filter is cached in an option, 'jetpack_sitemap_post_types', |
||
97 | * so this filter only has to be applied once per generation. |
||
98 | * |
||
99 | * @since 4.8.0 |
||
100 | */ |
||
101 | apply_filters( |
||
102 | 'jetpack_sitemap_post_types', |
||
103 | array( 'post', 'page' ) |
||
104 | ) |
||
105 | ); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Update the sitemap. |
||
110 | * |
||
111 | * All we do here is call build_next_sitemap_file a bunch of times. |
||
112 | * |
||
113 | * @since 4.8.0 |
||
114 | */ |
||
115 | public function update_sitemap() { |
||
116 | if ( $this->logger ) { |
||
117 | $this->logger->report( '-- Updating...' ); |
||
118 | if ( ! class_exists( 'DOMDocument' ) ) { |
||
119 | $this->logger->report( |
||
120 | __( |
||
121 | '-- WARNING: Jetpack can not load necessary XML manipulation libraries. ' |
||
122 | . 'This can happen if XML support in PHP is not enabled on your server. ' |
||
123 | . 'XML support is highly recommended for WordPress and Jetpack, please enable ' |
||
124 | . 'it or contact your hosting provider about it.', |
||
125 | 'jetpack' |
||
126 | ), |
||
127 | true |
||
128 | ); |
||
129 | } |
||
130 | } |
||
131 | |||
132 | for ( $i = 1; $i <= JP_SITEMAP_UPDATE_SIZE; $i++ ) { |
||
133 | $this->build_next_sitemap_file(); |
||
134 | } |
||
135 | |||
136 | if ( $this->logger ) { |
||
137 | $this->logger->report( '-- ...done for now.' ); |
||
138 | $this->logger->time(); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Generate the next sitemap file. |
||
144 | * |
||
145 | * Reads the most recent state of the sitemap generation phase, |
||
146 | * constructs the next file, and updates the state. |
||
147 | * |
||
148 | * @since 4.8.0 |
||
149 | */ |
||
150 | private function build_next_sitemap_file() { |
||
151 | // Get the most recent state, and lock the state. |
||
152 | $state = Jetpack_Sitemap_State::check_out(); |
||
153 | |||
154 | // Do nothing if the state was locked. |
||
155 | if ( false === $state ) { |
||
156 | return; |
||
157 | } |
||
158 | |||
159 | // Otherwise, branch on the sitemap-type key of $state. |
||
160 | switch ( $state['sitemap-type'] ) { |
||
161 | case JP_PAGE_SITEMAP_TYPE: |
||
162 | $this->build_next_sitemap_of_type( |
||
163 | JP_PAGE_SITEMAP_TYPE, |
||
164 | array( $this, 'build_one_page_sitemap' ), |
||
165 | $state |
||
166 | ); |
||
167 | break; |
||
168 | |||
169 | case JP_PAGE_SITEMAP_INDEX_TYPE: |
||
170 | $this->build_next_sitemap_index_of_type( |
||
171 | JP_PAGE_SITEMAP_INDEX_TYPE, |
||
172 | JP_IMAGE_SITEMAP_TYPE, |
||
173 | $state |
||
174 | ); |
||
175 | break; |
||
176 | |||
177 | case JP_IMAGE_SITEMAP_TYPE: |
||
178 | $this->build_next_sitemap_of_type( |
||
179 | JP_IMAGE_SITEMAP_TYPE, |
||
180 | array( $this, 'build_one_image_sitemap' ), |
||
181 | $state |
||
182 | ); |
||
183 | break; |
||
184 | |||
185 | case JP_IMAGE_SITEMAP_INDEX_TYPE: |
||
186 | $this->build_next_sitemap_index_of_type( |
||
187 | JP_IMAGE_SITEMAP_INDEX_TYPE, |
||
188 | JP_VIDEO_SITEMAP_TYPE, |
||
189 | $state |
||
190 | ); |
||
191 | break; |
||
192 | |||
193 | case JP_VIDEO_SITEMAP_TYPE: |
||
194 | $this->build_next_sitemap_of_type( |
||
195 | JP_VIDEO_SITEMAP_TYPE, |
||
196 | array( $this, 'build_one_video_sitemap' ), |
||
197 | $state |
||
198 | ); |
||
199 | break; |
||
200 | |||
201 | case JP_VIDEO_SITEMAP_INDEX_TYPE: |
||
202 | $this->build_next_sitemap_index_of_type( |
||
203 | JP_VIDEO_SITEMAP_INDEX_TYPE, |
||
204 | JP_MASTER_SITEMAP_TYPE, |
||
205 | $state |
||
206 | ); |
||
207 | break; |
||
208 | |||
209 | case JP_MASTER_SITEMAP_TYPE: |
||
210 | $this->build_master_sitemap( $state['max'] ); |
||
211 | |||
212 | // Reset the state and quit. |
||
213 | Jetpack_Sitemap_State::reset( |
||
214 | JP_PAGE_SITEMAP_TYPE |
||
215 | ); |
||
216 | |||
217 | if ( $this->logger ) { |
||
218 | $this->logger->report( '-- Finished.' ); |
||
219 | $this->logger->time(); |
||
220 | } |
||
221 | |||
222 | die(); |
||
223 | |||
224 | default: |
||
225 | // Otherwise, reset the state. |
||
226 | Jetpack_Sitemap_State::reset( |
||
227 | JP_PAGE_SITEMAP_TYPE |
||
228 | ); |
||
229 | die(); |
||
230 | } // End switch(). |
||
231 | |||
232 | // Unlock the state. |
||
233 | Jetpack_Sitemap_State::unlock(); |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * Build the next sitemap of a given type and update the sitemap state. |
||
238 | * |
||
239 | * @since 4.8.0 |
||
240 | * |
||
241 | * @param string $sitemap_type The type of the sitemap being generated. |
||
242 | * @param callback $build_one A callback which builds a single sitemap file. |
||
243 | * @param array $state A sitemap state. |
||
244 | */ |
||
245 | private function build_next_sitemap_of_type( $sitemap_type, $build_one, $state ) { |
||
246 | $index_type = jp_sitemap_index_type_of( $sitemap_type ); |
||
247 | |||
248 | // Try to build a sitemap. |
||
249 | $result = call_user_func_array( |
||
250 | $build_one, |
||
251 | array( |
||
252 | $state['number'] + 1, |
||
253 | $state['last-added'], |
||
254 | ) |
||
255 | ); |
||
256 | |||
257 | View Code Duplication | if ( false === $result ) { |
|
258 | // If no sitemap was generated, advance to the next type. |
||
259 | Jetpack_Sitemap_State::check_in( array( |
||
260 | 'sitemap-type' => $index_type, |
||
261 | 'last-added' => 0, |
||
262 | 'number' => 0, |
||
263 | 'last-modified' => '1970-01-01 00:00:00', |
||
264 | ) ); |
||
265 | |||
266 | if ( $this->logger ) { |
||
267 | $this->logger->report( "-- Cleaning Up $sitemap_type" ); |
||
268 | } |
||
269 | |||
270 | // Clean up old files. |
||
271 | $this->librarian->delete_numbered_sitemap_rows_after( |
||
272 | $state['number'], $sitemap_type |
||
273 | ); |
||
274 | |||
275 | return; |
||
276 | } |
||
277 | |||
278 | // Otherwise, update the state. |
||
279 | Jetpack_Sitemap_State::check_in( array( |
||
280 | 'sitemap-type' => $state['sitemap-type'], |
||
281 | 'last-added' => $result['last_id'], |
||
282 | 'number' => $state['number'] + 1, |
||
283 | 'last-modified' => $result['last_modified'], |
||
284 | ) ); |
||
285 | |||
286 | if ( true === $result['any_left'] ) { |
||
287 | // If there's more work to be done with this type, return. |
||
288 | return; |
||
289 | } |
||
290 | |||
291 | // Otherwise, advance state to the next sitemap type. |
||
292 | Jetpack_Sitemap_State::check_in( array( |
||
293 | 'sitemap-type' => $index_type, |
||
294 | 'last-added' => 0, |
||
295 | 'number' => 0, |
||
296 | 'last-modified' => '1970-01-01 00:00:00', |
||
297 | ) ); |
||
298 | |||
299 | if ( $this->logger ) { |
||
300 | $this->logger->report( "-- Cleaning Up $sitemap_type" ); |
||
301 | } |
||
302 | |||
303 | // Clean up old files. |
||
304 | $this->librarian->delete_numbered_sitemap_rows_after( |
||
305 | $state['number'] + 1, $sitemap_type |
||
306 | ); |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Build the next sitemap index of a given type and update the state. |
||
311 | * |
||
312 | * @since 4.8.0 |
||
313 | * |
||
314 | * @param string $index_type The type of index being generated. |
||
315 | * @param string $next_type The next type to generate after this one. |
||
316 | * @param array $state A sitemap state. |
||
317 | */ |
||
318 | private function build_next_sitemap_index_of_type( $index_type, $next_type, $state ) { |
||
319 | $sitemap_type = jp_sitemap_child_type_of( $index_type ); |
||
320 | |||
321 | // If only 0 or 1 sitemaps were built, advance to the next type and return. |
||
322 | if ( 1 >= $state['max'][ $sitemap_type ]['number'] ) { |
||
323 | Jetpack_Sitemap_State::check_in( array( |
||
324 | 'sitemap-type' => $next_type, |
||
325 | 'last-added' => 0, |
||
326 | 'number' => 0, |
||
327 | 'last-modified' => '1970-01-01 00:00:00', |
||
328 | ) ); |
||
329 | |||
330 | if ( $this->logger ) { |
||
331 | $this->logger->report( "-- Cleaning Up $index_type" ); |
||
332 | } |
||
333 | |||
334 | // There are no indices of this type. |
||
335 | $this->librarian->delete_numbered_sitemap_rows_after( |
||
336 | 0, $index_type |
||
337 | ); |
||
338 | |||
339 | return; |
||
340 | } |
||
341 | |||
342 | // Otherwise, try to build a sitemap index. |
||
343 | $result = $this->build_one_sitemap_index( |
||
344 | $state['number'] + 1, |
||
345 | $state['last-added'], |
||
346 | $state['last-modified'], |
||
347 | $index_type |
||
348 | ); |
||
349 | |||
350 | // If no index was built, advance to the next type and return. |
||
351 | View Code Duplication | if ( false === $result ) { |
|
352 | Jetpack_Sitemap_State::check_in( array( |
||
353 | 'sitemap-type' => $next_type, |
||
354 | 'last-added' => 0, |
||
355 | 'number' => 0, |
||
356 | 'last-modified' => '1970-01-01 00:00:00', |
||
357 | ) ); |
||
358 | |||
359 | if ( $this->logger ) { |
||
360 | $this->logger->report( "-- Cleaning Up $index_type" ); |
||
361 | } |
||
362 | |||
363 | // Clean up old files. |
||
364 | $this->librarian->delete_numbered_sitemap_rows_after( |
||
365 | $state['number'], $index_type |
||
366 | ); |
||
367 | |||
368 | return; |
||
369 | } |
||
370 | |||
371 | // Otherwise, check in the state. |
||
372 | Jetpack_Sitemap_State::check_in( array( |
||
373 | 'sitemap-type' => $index_type, |
||
374 | 'last-added' => $result['last_id'], |
||
375 | 'number' => $state['number'] + 1, |
||
376 | 'last-modified' => $result['last_modified'], |
||
377 | ) ); |
||
378 | |||
379 | // If there are still sitemaps left to index, return. |
||
380 | if ( true === $result['any_left'] ) { |
||
381 | return; |
||
382 | } |
||
383 | |||
384 | // Otherwise, advance to the next type. |
||
385 | Jetpack_Sitemap_State::check_in( array( |
||
386 | 'sitemap-type' => $next_type, |
||
387 | 'last-added' => 0, |
||
388 | 'number' => 0, |
||
389 | 'last-modified' => '1970-01-01 00:00:00', |
||
390 | ) ); |
||
391 | |||
392 | if ( $this->logger ) { |
||
393 | $this->logger->report( "-- Cleaning Up $index_type" ); |
||
394 | } |
||
395 | |||
396 | // We're done generating indices of this type. |
||
397 | $this->librarian->delete_numbered_sitemap_rows_after( |
||
398 | $state['number'] + 1, $index_type |
||
399 | ); |
||
400 | |||
401 | return; |
||
402 | } |
||
403 | |||
404 | /** |
||
405 | * Builds the master sitemap index. |
||
406 | * |
||
407 | * @param array $max Array of sitemap types with max index and datetime. |
||
408 | * |
||
409 | * @since 4.8.0 |
||
410 | */ |
||
411 | private function build_master_sitemap( $max ) { |
||
412 | if ( $this->logger ) { |
||
413 | $this->logger->report( '-- Building Master Sitemap.' ); |
||
414 | } |
||
415 | |||
416 | $buffer = new Jetpack_Sitemap_Buffer_Master( |
||
417 | JP_SITEMAP_MAX_ITEMS, |
||
418 | JP_SITEMAP_MAX_BYTES |
||
419 | ); |
||
420 | |||
421 | View Code Duplication | if ( 0 < $max[ JP_PAGE_SITEMAP_TYPE ]['number'] ) { |
|
422 | if ( 1 === $max[ JP_PAGE_SITEMAP_TYPE ]['number'] ) { |
||
423 | $page['filename'] = jp_sitemap_filename( JP_PAGE_SITEMAP_TYPE, 1 ); |
||
424 | $page['last_modified'] = jp_sitemap_datetime( $max[ JP_PAGE_SITEMAP_TYPE ]['lastmod'] ); |
||
425 | } else { |
||
426 | $page['filename'] = jp_sitemap_filename( |
||
427 | JP_PAGE_SITEMAP_INDEX_TYPE, |
||
428 | $max[ JP_PAGE_SITEMAP_INDEX_TYPE ]['number'] |
||
429 | ); |
||
430 | $page['last_modified'] = jp_sitemap_datetime( $max[ JP_PAGE_SITEMAP_INDEX_TYPE ]['lastmod'] ); |
||
431 | } |
||
432 | |||
433 | $buffer->append( |
||
434 | array( |
||
435 | 'sitemap' => array( |
||
436 | 'loc' => $this->finder->construct_sitemap_url( $page['filename'] ), |
||
437 | 'lastmod' => $page['last_modified'], |
||
438 | ), |
||
439 | ) |
||
440 | ); |
||
441 | } |
||
442 | |||
443 | View Code Duplication | if ( 0 < $max[ JP_IMAGE_SITEMAP_TYPE ]['number'] ) { |
|
444 | if ( 1 === $max[ JP_IMAGE_SITEMAP_TYPE ]['number'] ) { |
||
445 | $image['filename'] = jp_sitemap_filename( JP_IMAGE_SITEMAP_TYPE, 1 ); |
||
446 | $image['last_modified'] = jp_sitemap_datetime( $max[ JP_IMAGE_SITEMAP_TYPE ]['lastmod'] ); |
||
447 | } else { |
||
448 | $image['filename'] = jp_sitemap_filename( |
||
449 | JP_IMAGE_SITEMAP_INDEX_TYPE, |
||
450 | $max[ JP_IMAGE_SITEMAP_INDEX_TYPE ]['number'] |
||
451 | ); |
||
452 | $image['last_modified'] = jp_sitemap_datetime( $max[ JP_IMAGE_SITEMAP_INDEX_TYPE ]['lastmod'] ); |
||
453 | } |
||
454 | |||
455 | $buffer->append( |
||
456 | array( |
||
457 | 'sitemap' => array( |
||
458 | 'loc' => $this->finder->construct_sitemap_url( $image['filename'] ), |
||
459 | 'lastmod' => $image['last_modified'], |
||
460 | ), |
||
461 | ) |
||
462 | ); |
||
463 | } |
||
464 | |||
465 | View Code Duplication | if ( 0 < $max[ JP_VIDEO_SITEMAP_TYPE ]['number'] ) { |
|
466 | if ( 1 === $max[ JP_VIDEO_SITEMAP_TYPE ]['number'] ) { |
||
467 | $video['filename'] = jp_sitemap_filename( JP_VIDEO_SITEMAP_TYPE, 1 ); |
||
468 | $video['last_modified'] = $max[ JP_VIDEO_SITEMAP_TYPE ]['lastmod']; |
||
469 | } else { |
||
470 | $video['filename'] = jp_sitemap_filename( |
||
471 | JP_VIDEO_SITEMAP_INDEX_TYPE, |
||
472 | $max[ JP_VIDEO_SITEMAP_INDEX_TYPE ]['number'] |
||
473 | ); |
||
474 | $video['last_modified'] = $max[ JP_VIDEO_SITEMAP_INDEX_TYPE ]['lastmod']; |
||
475 | } |
||
476 | |||
477 | $buffer->append( |
||
478 | array( |
||
479 | 'sitemap' => array( |
||
480 | 'loc' => $this->finder->construct_sitemap_url( $video['filename'] ), |
||
481 | 'lastmod' => $video['last_modified'], |
||
482 | ), |
||
483 | ) |
||
484 | ); |
||
485 | } |
||
486 | |||
487 | $this->librarian->store_sitemap_data( |
||
488 | 0, |
||
489 | JP_MASTER_SITEMAP_TYPE, |
||
490 | $buffer->contents(), |
||
491 | '' |
||
492 | ); |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Build and store a single page sitemap. Returns false if no sitemap is built. |
||
497 | * |
||
498 | * Side effect: Create/update a sitemap row. |
||
499 | * |
||
500 | * @access private |
||
501 | * @since 4.8.0 |
||
502 | * |
||
503 | * @param int $number The number of the current sitemap. |
||
504 | * @param int $from_id The greatest lower bound of the IDs of the posts to be included. |
||
505 | * |
||
506 | * @return bool|array @args { |
||
507 | * @type int $last_id The ID of the last item to be successfully added to the buffer. |
||
508 | * @type bool $any_left 'true' if there are items which haven't been saved to a sitemap, 'false' otherwise. |
||
509 | * @type string $last_modified The most recent timestamp to appear on the sitemap. |
||
510 | * } |
||
511 | */ |
||
512 | public function build_one_page_sitemap( $number, $from_id ) { |
||
513 | $last_post_id = $from_id; |
||
514 | $any_posts_left = true; |
||
515 | |||
516 | if ( $this->logger ) { |
||
517 | $debug_name = jp_sitemap_filename( JP_PAGE_SITEMAP_TYPE, $number ); |
||
518 | $this->logger->report( "-- Building $debug_name" ); |
||
519 | } |
||
520 | |||
521 | $buffer = new Jetpack_Sitemap_Buffer_Page( |
||
522 | JP_SITEMAP_MAX_ITEMS, |
||
523 | JP_SITEMAP_MAX_BYTES |
||
524 | ); |
||
525 | |||
526 | // Add entry for the main page (only if we're at the first one). |
||
527 | if ( 1 === $number ) { |
||
528 | $item_array = array( |
||
529 | 'url' => array( |
||
530 | 'loc' => home_url(), |
||
531 | ), |
||
532 | ); |
||
533 | |||
534 | /** |
||
535 | * Filter associative array with data to build <url> node |
||
536 | * and its descendants for site home. |
||
537 | * |
||
538 | * @module sitemaps |
||
539 | * |
||
540 | * @since 3.9.0 |
||
541 | * |
||
542 | * @param array $blog_home Data to build parent and children nodes for site home. |
||
543 | */ |
||
544 | $item_array = apply_filters( 'jetpack_sitemap_url_home', $item_array ); |
||
545 | |||
546 | $buffer->append( $item_array ); |
||
547 | } |
||
548 | |||
549 | // Add as many items to the buffer as possible. |
||
550 | while ( false === $buffer->is_full() ) { |
||
551 | $posts = $this->librarian->query_posts_after_id( |
||
552 | $last_post_id, JP_SITEMAP_BATCH_SIZE |
||
553 | ); |
||
554 | |||
555 | if ( null == $posts ) { // WPCS: loose comparison ok. |
||
556 | $any_posts_left = false; |
||
557 | break; |
||
558 | } |
||
559 | |||
560 | foreach ( $posts as $post ) { |
||
561 | $current_item = $this->post_to_sitemap_item( $post ); |
||
562 | |||
563 | if ( true === $buffer->append( $current_item['xml'] ) ) { |
||
564 | $last_post_id = $post->ID; |
||
565 | $buffer->view_time( $current_item['last_modified'] ); |
||
566 | } else { |
||
567 | break; |
||
568 | } |
||
569 | } |
||
570 | } |
||
571 | |||
572 | // If no items were added, return false. |
||
573 | if ( true === $buffer->is_empty() ) { |
||
574 | return false; |
||
575 | } |
||
576 | |||
577 | /** |
||
578 | * Filter sitemap before rendering it as XML. |
||
579 | * |
||
580 | * @module sitemaps |
||
581 | * |
||
582 | * @since 3.9.0 |
||
583 | * @since 5.3.0 returns an element of DOMDocument type instead of SimpleXMLElement |
||
584 | * |
||
585 | * @param DOMDocument $doc Data tree for sitemap. |
||
586 | * @param string $last_modified Date of last modification. |
||
587 | */ |
||
588 | $tree = apply_filters( |
||
589 | 'jetpack_print_sitemap', |
||
590 | $buffer->get_document(), |
||
591 | $buffer->last_modified() |
||
592 | ); |
||
593 | |||
594 | // Store the buffer as the content of a sitemap row. |
||
595 | $this->librarian->store_sitemap_data( |
||
596 | $number, |
||
597 | JP_PAGE_SITEMAP_TYPE, |
||
598 | $buffer->contents(), |
||
599 | $buffer->last_modified() |
||
600 | ); |
||
601 | |||
602 | /* |
||
603 | * Now report back with the ID of the last post ID to be |
||
604 | * successfully added and whether there are any posts left. |
||
605 | */ |
||
606 | return array( |
||
607 | 'last_id' => $last_post_id, |
||
608 | 'any_left' => $any_posts_left, |
||
609 | 'last_modified' => $buffer->last_modified(), |
||
610 | ); |
||
611 | } |
||
612 | |||
613 | /** |
||
614 | * Build and store a single image sitemap. Returns false if no sitemap is built. |
||
615 | * |
||
616 | * Side effect: Create/update an image sitemap row. |
||
617 | * |
||
618 | * @access private |
||
619 | * @since 4.8.0 |
||
620 | * |
||
621 | * @param int $number The number of the current sitemap. |
||
622 | * @param int $from_id The greatest lower bound of the IDs of the posts to be included. |
||
623 | * |
||
624 | * @return bool|array @args { |
||
625 | * @type int $last_id The ID of the last item to be successfully added to the buffer. |
||
626 | * @type bool $any_left 'true' if there are items which haven't been saved to a sitemap, 'false' otherwise. |
||
627 | * @type string $last_modified The most recent timestamp to appear on the sitemap. |
||
628 | * } |
||
629 | */ |
||
630 | View Code Duplication | public function build_one_image_sitemap( $number, $from_id ) { |
|
631 | $last_post_id = $from_id; |
||
632 | $any_posts_left = true; |
||
633 | |||
634 | if ( $this->logger ) { |
||
635 | $debug_name = jp_sitemap_filename( JP_IMAGE_SITEMAP_TYPE, $number ); |
||
636 | $this->logger->report( "-- Building $debug_name" ); |
||
637 | } |
||
638 | |||
639 | $buffer = new Jetpack_Sitemap_Buffer_Image( |
||
640 | JP_SITEMAP_MAX_ITEMS, |
||
641 | JP_SITEMAP_MAX_BYTES |
||
642 | ); |
||
643 | |||
644 | // Add as many items to the buffer as possible. |
||
645 | while ( false === $buffer->is_full() ) { |
||
646 | $posts = $this->librarian->query_images_after_id( |
||
647 | $last_post_id, JP_SITEMAP_BATCH_SIZE |
||
648 | ); |
||
649 | |||
650 | if ( null == $posts ) { // WPCS: loose comparison ok. |
||
651 | $any_posts_left = false; |
||
652 | break; |
||
653 | } |
||
654 | |||
655 | foreach ( $posts as $post ) { |
||
656 | $current_item = $this->image_post_to_sitemap_item( $post ); |
||
657 | |||
658 | if ( true === $buffer->append( $current_item['xml'] ) ) { |
||
659 | $last_post_id = $post->ID; |
||
660 | $buffer->view_time( $current_item['last_modified'] ); |
||
661 | } else { |
||
662 | break; |
||
663 | } |
||
664 | } |
||
665 | } |
||
666 | |||
667 | // If no items were added, return false. |
||
668 | if ( true === $buffer->is_empty() ) { |
||
669 | return false; |
||
670 | } |
||
671 | |||
672 | // Store the buffer as the content of a jp_sitemap post. |
||
673 | $this->librarian->store_sitemap_data( |
||
674 | $number, |
||
675 | JP_IMAGE_SITEMAP_TYPE, |
||
676 | $buffer->contents(), |
||
677 | $buffer->last_modified() |
||
678 | ); |
||
679 | |||
680 | /* |
||
681 | * Now report back with the ID of the last post to be |
||
682 | * successfully added and whether there are any posts left. |
||
683 | */ |
||
684 | return array( |
||
685 | 'last_id' => $last_post_id, |
||
686 | 'any_left' => $any_posts_left, |
||
687 | 'last_modified' => $buffer->last_modified(), |
||
688 | ); |
||
689 | } |
||
690 | |||
691 | /** |
||
692 | * Build and store a single video sitemap. Returns false if no sitemap is built. |
||
693 | * |
||
694 | * Side effect: Create/update an video sitemap row. |
||
695 | * |
||
696 | * @access private |
||
697 | * @since 4.8.0 |
||
698 | * |
||
699 | * @param int $number The number of the current sitemap. |
||
700 | * @param int $from_id The greatest lower bound of the IDs of the posts to be included. |
||
701 | * |
||
702 | * @return bool|array @args { |
||
703 | * @type int $last_id The ID of the last item to be successfully added to the buffer. |
||
704 | * @type bool $any_left 'true' if there are items which haven't been saved to a sitemap, 'false' otherwise. |
||
705 | * @type string $last_modified The most recent timestamp to appear on the sitemap. |
||
706 | * } |
||
707 | */ |
||
708 | View Code Duplication | public function build_one_video_sitemap( $number, $from_id ) { |
|
709 | $last_post_id = $from_id; |
||
710 | $any_posts_left = true; |
||
711 | |||
712 | if ( $this->logger ) { |
||
713 | $debug_name = jp_sitemap_filename( JP_VIDEO_SITEMAP_TYPE, $number ); |
||
714 | $this->logger->report( "-- Building $debug_name" ); |
||
715 | } |
||
716 | |||
717 | $buffer = new Jetpack_Sitemap_Buffer_Video( |
||
718 | JP_SITEMAP_MAX_ITEMS, |
||
719 | JP_SITEMAP_MAX_BYTES |
||
720 | ); |
||
721 | |||
722 | // Add as many items to the buffer as possible. |
||
723 | while ( false === $buffer->is_full() ) { |
||
724 | $posts = $this->librarian->query_videos_after_id( |
||
725 | $last_post_id, JP_SITEMAP_BATCH_SIZE |
||
726 | ); |
||
727 | |||
728 | if ( null == $posts ) { // WPCS: loose comparison ok. |
||
729 | $any_posts_left = false; |
||
730 | break; |
||
731 | } |
||
732 | |||
733 | foreach ( $posts as $post ) { |
||
734 | $current_item = $this->video_post_to_sitemap_item( $post ); |
||
735 | |||
736 | if ( true === $buffer->append( $current_item['xml'] ) ) { |
||
737 | $last_post_id = $post->ID; |
||
738 | $buffer->view_time( $current_item['last_modified'] ); |
||
739 | } else { |
||
740 | break; |
||
741 | } |
||
742 | } |
||
743 | } |
||
744 | |||
745 | // If no items were added, return false. |
||
746 | if ( true === $buffer->is_empty() ) { |
||
747 | return false; |
||
748 | } |
||
749 | |||
750 | if ( false === $buffer->is_empty() ) { |
||
751 | $this->librarian->store_sitemap_data( |
||
752 | $number, |
||
753 | JP_VIDEO_SITEMAP_TYPE, |
||
754 | $buffer->contents(), |
||
755 | $buffer->last_modified() |
||
756 | ); |
||
757 | } |
||
758 | |||
759 | /* |
||
760 | * Now report back with the ID of the last post to be |
||
761 | * successfully added and whether there are any posts left. |
||
762 | */ |
||
763 | return array( |
||
764 | 'last_id' => $last_post_id, |
||
765 | 'any_left' => $any_posts_left, |
||
766 | 'last_modified' => $buffer->last_modified(), |
||
767 | ); |
||
768 | } |
||
769 | |||
770 | /** |
||
771 | * Build and store a single page sitemap index. Return false if no index is built. |
||
772 | * |
||
773 | * Side effect: Create/update a sitemap index row. |
||
774 | * |
||
775 | * @access private |
||
776 | * @since 4.8.0 |
||
777 | * |
||
778 | * @param int $number The number of the current sitemap index. |
||
779 | * @param int $from_id The greatest lower bound of the IDs of the sitemaps to be included. |
||
780 | * @param string $datetime Datetime of previous sitemap in 'YYYY-MM-DD hh:mm:ss' format. |
||
781 | * @param string $index_type Sitemap index type. |
||
782 | * |
||
783 | * @return bool|array @args { |
||
784 | * @type int $last_id The ID of the last item to be successfully added to the buffer. |
||
785 | * @type bool $any_left 'true' if there are items which haven't been saved to a sitemap, 'false' otherwise. |
||
786 | * @type string $last_modified The most recent timestamp to appear on the sitemap. |
||
787 | * } |
||
788 | */ |
||
789 | private function build_one_sitemap_index( $number, $from_id, $datetime, $index_type ) { |
||
790 | $last_sitemap_id = $from_id; |
||
791 | $any_sitemaps_left = true; |
||
792 | |||
793 | // Check the datetime format. |
||
794 | $datetime = jp_sitemap_datetime( $datetime ); |
||
795 | |||
796 | $sitemap_type = jp_sitemap_child_type_of( $index_type ); |
||
797 | |||
798 | if ( $this->logger ) { |
||
799 | $index_debug_name = jp_sitemap_filename( $index_type, $number ); |
||
800 | $this->logger->report( "-- Building $index_debug_name" ); |
||
801 | } |
||
802 | |||
803 | $buffer = new Jetpack_Sitemap_Buffer_Master( |
||
804 | JP_SITEMAP_MAX_ITEMS, |
||
805 | JP_SITEMAP_MAX_BYTES, |
||
806 | $datetime |
||
807 | ); |
||
808 | |||
809 | // Add pointer to the previous sitemap index (unless we're at the first one). |
||
810 | if ( 1 !== $number ) { |
||
811 | $i = $number - 1; |
||
812 | $prev_index_url = $this->finder->construct_sitemap_url( |
||
813 | jp_sitemap_filename( $index_type, $i ) |
||
814 | ); |
||
815 | |||
816 | $item_array = array( |
||
817 | 'sitemap' => array( |
||
818 | 'loc' => $prev_index_url, |
||
819 | 'lastmod' => $datetime, |
||
820 | ), |
||
821 | ); |
||
822 | |||
823 | $buffer->append( $item_array ); |
||
824 | } |
||
825 | |||
826 | // Add as many items to the buffer as possible. |
||
827 | while ( false === $buffer->is_full() ) { |
||
828 | // Retrieve a batch of posts (in order). |
||
829 | $posts = $this->librarian->query_sitemaps_after_id( |
||
830 | $sitemap_type, $last_sitemap_id, JP_SITEMAP_BATCH_SIZE |
||
831 | ); |
||
832 | |||
833 | // If there were no posts to get, make a note. |
||
834 | if ( null == $posts ) { // WPCS: loose comparison ok. |
||
835 | $any_sitemaps_left = false; |
||
836 | break; |
||
837 | } |
||
838 | |||
839 | // Otherwise, loop through each post in the batch. |
||
840 | foreach ( $posts as $post ) { |
||
841 | // Generate the sitemap XML for the post. |
||
842 | $current_item = $this->sitemap_row_to_index_item( (array) $post ); |
||
843 | |||
844 | // Try adding this item to the buffer. |
||
845 | if ( true === $buffer->append( $current_item['xml'] ) ) { |
||
846 | $last_sitemap_id = $post['ID']; |
||
847 | $buffer->view_time( $current_item['last_modified'] ); |
||
848 | } else { |
||
849 | // Otherwise stop looping through posts. |
||
850 | break; |
||
851 | } |
||
852 | } |
||
853 | } |
||
854 | |||
855 | // If no items were added, return false. |
||
856 | if ( true === $buffer->is_empty() ) { |
||
857 | return false; |
||
858 | } |
||
859 | |||
860 | $this->librarian->store_sitemap_data( |
||
861 | $number, |
||
862 | $index_type, |
||
863 | $buffer->contents(), |
||
864 | $buffer->last_modified() |
||
865 | ); |
||
866 | |||
867 | /* |
||
868 | * Now report back with the ID of the last sitemap post ID to |
||
869 | * be successfully added, whether there are any sitemap posts |
||
870 | * left, and the most recent modification time seen. |
||
871 | */ |
||
872 | return array( |
||
873 | 'last_id' => $last_sitemap_id, |
||
874 | 'any_left' => $any_sitemaps_left, |
||
875 | 'last_modified' => $buffer->last_modified(), |
||
876 | ); |
||
877 | } |
||
878 | |||
879 | /** |
||
880 | * Construct the sitemap index url entry for a sitemap row. |
||
881 | * |
||
882 | * @link http://www.sitemaps.org/protocol.html#sitemapIndex_sitemap |
||
883 | * |
||
884 | * @access private |
||
885 | * @since 4.8.0 |
||
886 | * |
||
887 | * @param array $row The sitemap data to be processed. |
||
888 | * |
||
889 | * @return string An XML fragment representing the post URL. |
||
890 | */ |
||
891 | private function sitemap_row_to_index_item( $row ) { |
||
892 | $url = $this->finder->construct_sitemap_url( $row['post_title'] ); |
||
893 | |||
894 | $item_array = array( |
||
895 | 'sitemap' => array( |
||
896 | 'loc' => $url, |
||
897 | 'lastmod' => jp_sitemap_datetime( $row['post_date'] ), |
||
898 | ), |
||
899 | ); |
||
900 | |||
901 | return array( |
||
902 | 'xml' => $item_array, |
||
903 | 'last_modified' => $row['post_date'], |
||
904 | ); |
||
905 | } |
||
906 | |||
907 | /** |
||
908 | * Build and return the news sitemap xml. Note that the result of this |
||
909 | * function is cached in the transient 'jetpack_news_sitemap_xml'. |
||
910 | * |
||
911 | * @access public |
||
912 | * @since 4.8.0 |
||
913 | * |
||
914 | * @return string The news sitemap xml. |
||
915 | */ |
||
916 | public function news_sitemap_xml() { |
||
917 | $the_stored_news_sitemap = get_transient( 'jetpack_news_sitemap_xml' ); |
||
918 | |||
919 | if ( false === $the_stored_news_sitemap ) { |
||
920 | |||
921 | if ( $this->logger ) { |
||
922 | $this->logger->report( 'Beginning news sitemap generation.' ); |
||
923 | } |
||
924 | |||
925 | /** |
||
926 | * Filter limit of entries to include in news sitemap. |
||
927 | * |
||
928 | * @module sitemaps |
||
929 | * |
||
930 | * @since 3.9.0 |
||
931 | * |
||
932 | * @param int $count Number of entries to include in news sitemap. |
||
933 | */ |
||
934 | $item_limit = apply_filters( |
||
935 | 'jetpack_sitemap_news_sitemap_count', |
||
936 | JP_NEWS_SITEMAP_MAX_ITEMS |
||
937 | ); |
||
938 | |||
939 | $buffer = new Jetpack_Sitemap_Buffer_News( |
||
940 | min( $item_limit, JP_NEWS_SITEMAP_MAX_ITEMS ), |
||
941 | JP_SITEMAP_MAX_BYTES |
||
942 | ); |
||
943 | |||
944 | $posts = $this->librarian->query_most_recent_posts( JP_NEWS_SITEMAP_MAX_ITEMS ); |
||
945 | |||
946 | foreach ( $posts as $post ) { |
||
947 | $current_item = $this->post_to_news_sitemap_item( $post ); |
||
948 | |||
949 | if ( false === $buffer->append( $current_item['xml'] ) ) { |
||
950 | break; |
||
951 | } |
||
952 | } |
||
953 | |||
954 | if ( $this->logger ) { |
||
955 | $this->logger->time( 'End news sitemap generation.' ); |
||
956 | } |
||
957 | |||
958 | $the_stored_news_sitemap = $buffer->contents(); |
||
959 | |||
960 | set_transient( |
||
961 | 'jetpack_news_sitemap_xml', |
||
962 | $the_stored_news_sitemap, |
||
963 | JP_NEWS_SITEMAP_INTERVAL |
||
964 | ); |
||
965 | } // End if(). |
||
966 | |||
967 | return $the_stored_news_sitemap; |
||
968 | } |
||
969 | |||
970 | /** |
||
971 | * Construct the sitemap url entry for a WP_Post. |
||
972 | * |
||
973 | * @link http://www.sitemaps.org/protocol.html#urldef |
||
974 | * @access private |
||
975 | * @since 4.8.0 |
||
976 | * |
||
977 | * @param WP_Post $post The post to be processed. |
||
978 | * |
||
979 | * @return array An array representing the post URL. |
||
980 | */ |
||
981 | private function post_to_sitemap_item( $post ) { |
||
1045 | |||
1046 | /** |
||
1047 | * Construct the image sitemap url entry for a WP_Post of image type. |
||
1048 | * |
||
1049 | * @link http://www.sitemaps.org/protocol.html#urldef |
||
1050 | * |
||
1051 | * @access private |
||
1052 | * @since 4.8.0 |
||
1053 | * |
||
1054 | * @param WP_Post $post The image post to be processed. |
||
1055 | * |
||
1056 | * @return string An XML fragment representing the post URL. |
||
1057 | */ |
||
1058 | private function image_post_to_sitemap_item( $post ) { |
||
1119 | |||
1120 | /** |
||
1121 | * Construct the video sitemap url entry for a WP_Post of video type. |
||
1122 | * |
||
1123 | * @link http://www.sitemaps.org/protocol.html#urldef |
||
1124 | * @link https://developers.google.com/webmasters/videosearch/sitemaps |
||
1125 | * |
||
1126 | * @access private |
||
1127 | * @since 4.8.0 |
||
1128 | * |
||
1129 | * @param WP_Post $post The video post to be processed. |
||
1130 | * |
||
1131 | * @return string An XML fragment representing the post URL. |
||
1132 | */ |
||
1133 | private function video_post_to_sitemap_item( $post ) { |
||
1204 | |||
1205 | /** |
||
1206 | * Construct the news sitemap url entry for a WP_Post. |
||
1207 | * |
||
1208 | * @link http://www.sitemaps.org/protocol.html#urldef |
||
1209 | * |
||
1210 | * @access private |
||
1211 | * @since 4.8.0 |
||
1212 | * |
||
1213 | * @param WP_Post $post The post to be processed. |
||
1214 | * |
||
1215 | * @return string An XML fragment representing the post URL. |
||
1216 | */ |
||
1217 | private function post_to_news_sitemap_item( $post ) { |
||
1296 | } |
||
1297 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..