PluginProbe
FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel / 1.8.0
FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel v1.8.0
1.8.0 1.7.1 1.7.0 1.6.0 1.5.2 trunk 0.1 0.2.0 0.2.1 0.3 0.3.1 0.3.2 0.3.3 0.3.4 0.4 0.4.1 0.4.2 0.4.3 1.0 1.1 1.2 1.3.1 1.4.0 1.4.1 1.5.0 All 27 releases
flywp / includes / StaticSite / Engine / Discovery / WpGateway.php

WpGateway.php in FlyWP Helper – Page Cache, Page Optimization, Emails for FlyWP Server Control Panel 1.8.0, at includes/StaticSite/Engine/Discovery/WpGateway.php

676 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FlyWP\StaticSite\Engine\Discovery;
4
5 use WP_Rewrite;
6 use WP_Term;
7
8 /**
9 * WordPress implementation of the gateway.
10 *
11 * Queries read IDs in batches and prime the object caches, so that link functions do not
12 * send one query for each object.
13 *
14 * @since 1.8.0
15 */
16 class WpGateway implements WordPressGateway {
17
18 /**
19 * {@inheritdoc}
20 */
21 public function home_url() {
22 return trailingslashit( home_url( '/' ) );
23 }
24
25 /**
26 * {@inheritdoc}
27 */
28 public function option( $name ) {
29 return get_option( $name );
30 }
31
32 /**
33 * {@inheritdoc}
34 */
35 public function apply_filters( $hook, $value, $arg = null ) {
36 return apply_filters( $hook, $value, $arg );
37 }
38
39 /**
40 * {@inheritdoc}
41 */
42 public function is_bulk_request() {
43 return ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) || wp_installing();
44 }
45
46 /**
47 * {@inheritdoc}
48 */
49 public function public_post_types() {
50 return array_values( array_diff( get_post_types( [ 'public' => true ], 'names' ), [ 'attachment' ] ) );
51 }
52
53 /**
54 * {@inheritdoc}
55 */
56 public function public_taxonomies() {
57 return array_values( get_taxonomies( [ 'public' => true ], 'names' ) );
58 }
59
60 /**
61 * {@inheritdoc}
62 */
63 public function post_rows( array $post_types, $after_id, $limit ) {
64 global $wpdb;
65
66 if ( empty( $post_types ) ) {
67 return [];
68 }
69
70 $this->flush_runtime_cache();
71
72 $rows = $wpdb->get_results(
73 $wpdb->prepare(
74 "SELECT ID, post_type, post_password, post_modified_gmt FROM {$wpdb->posts}
75 WHERE post_status = 'publish' AND post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' ) AND ID > %d
76 ORDER BY ID ASC LIMIT %d',
77 array_merge( array_values( $post_types ), [ (int) $after_id, (int) $limit ] )
78 ),
79 ARRAY_A
80 );
81
82 $rows = is_array( $rows ) ? $rows : [];
83
84 _prime_post_caches( array_map( 'intval', array_column( $rows, 'ID' ) ), true, false );
85
86 return array_map(
87 function ( $row ) {
88 return [
89 'id' => (int) $row['ID'],
90 'post_type' => $row['post_type'],
91 'password' => (string) $row['post_password'],
92 'modified_gmt' => $row['post_modified_gmt'],
93 ];
94 },
95 $rows
96 );
97 }
98
99 /**
100 * {@inheritdoc}
101 */
102 public function seo_robots_meta( array $post_ids ) {
103 global $wpdb;
104
105 $keys = [];
106
107 if ( defined( 'WPSEO_VERSION' ) ) {
108 $keys[] = RobotsMeta::YOAST_NOINDEX;
109 }
110
111 if ( class_exists( 'RankMath' ) ) {
112 $keys[] = RobotsMeta::RANK_MATH_ROBOTS;
113 }
114
115 if ( empty( $keys ) || empty( $post_ids ) ) {
116 return [];
117 }
118
119 $rows = $wpdb->get_results(
120 $wpdb->prepare(
121 "SELECT post_id, meta_key, meta_value FROM {$wpdb->postmeta}
122 WHERE post_id IN ( " . implode( ', ', array_fill( 0, count( $post_ids ), '%d' ) ) . ' ) AND meta_key IN ( ' . implode( ', ', array_fill( 0, count( $keys ), '%s' ) ) . ' )',
123 array_merge( array_map( 'intval', $post_ids ), $keys )
124 ),
125 ARRAY_A
126 );
127
128 return is_array( $rows ) ? $rows : [];
129 }
130
131 /**
132 * {@inheritdoc}
133 */
134 public function seo_term_meta_option() {
135 if ( ! defined( 'WPSEO_VERSION' ) ) {
136 return [];
137 }
138
139 $option = get_option( 'wpseo_taxonomy_meta' );
140
141 return is_array( $option ) ? $option : [];
142 }
143
144 /**
145 * {@inheritdoc}
146 */
147 public function seo_term_robots_meta( $after_id, $limit ) {
148 global $wpdb;
149
150 if ( ! class_exists( 'RankMath' ) ) {
151 return [];
152 }
153
154 $rows = $wpdb->get_results(
155 $wpdb->prepare(
156 "SELECT tm.term_id, tt.taxonomy, tm.meta_value FROM {$wpdb->termmeta} tm
157 INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_id = tm.term_id
158 WHERE tm.meta_key = %s AND tm.term_id > %d
159 ORDER BY tm.term_id ASC LIMIT %d",
160 RobotsMeta::RANK_MATH_ROBOTS,
161 (int) $after_id,
162 (int) $limit
163 ),
164 ARRAY_A
165 );
166
167 return is_array( $rows ) ? $rows : [];
168 }
169
170 /**
171 * {@inheritdoc}
172 */
173 public function post( $post_id ) {
174 $post = get_post( (int) $post_id );
175
176 if ( ! $post ) {
177 return null;
178 }
179
180 return [
181 'id' => (int) $post->ID,
182 'post_type' => $post->post_type,
183 'status' => $post->post_status,
184 'password' => (string) $post->post_password,
185 'author' => (int) $post->post_author,
186 'date' => $post->post_date,
187 'modified_gmt' => $post->post_modified_gmt,
188 'pages' => substr_count( (string) $post->post_content, '<!--nextpage-->' ) + 1,
189 ];
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function permalink( $post_id ) {
196 return $this->link( get_permalink( (int) $post_id ) );
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function object_permalink( $post ) {
203 return $this->link( get_permalink( $post ) );
204 }
205
206 /**
207 * {@inheritdoc}
208 */
209 public function post_page_url( $permalink, $page ) {
210 return $this->pretty_url( $permalink, (string) (int) $page, 'single_paged', 'page', $page );
211 }
212
213 /**
214 * {@inheritdoc}
215 */
216 public function post_has_children( $post_id, $post_type ) {
217 global $wpdb;
218
219 if ( ! is_post_type_hierarchical( $post_type ) ) {
220 return false;
221 }
222
223 return (bool) $wpdb->get_var(
224 $wpdb->prepare(
225 "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_type = %s AND post_status = 'publish' LIMIT 1",
226 (int) $post_id,
227 $post_type
228 )
229 );
230 }
231
232 /**
233 * {@inheritdoc}
234 */
235 public function published_count( $post_type ) {
236 $counts = wp_count_posts( $post_type );
237
238 return (int) ( $counts->publish ?? 0 );
239 }
240
241 /**
242 * {@inheritdoc}
243 */
244 public function newest_modified_gmt( array $post_types ) {
245 global $wpdb;
246
247 if ( empty( $post_types ) ) {
248 return null;
249 }
250
251 $value = $wpdb->get_var(
252 $wpdb->prepare(
253 "SELECT MAX(post_modified_gmt) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
254 array_values( $post_types )
255 )
256 );
257
258 return $value ? $value : null;
259 }
260
261 /**
262 * {@inheritdoc}
263 */
264 public function post_type_archive_link( $post_type ) {
265 return $this->link( get_post_type_archive_link( $post_type ) );
266 }
267
268 /**
269 * {@inheritdoc}
270 */
271 public function term_rows( $taxonomy, $after_id, $limit ) {
272 global $wpdb;
273
274 $rows = $wpdb->get_results(
275 $wpdb->prepare(
276 "SELECT tt.term_id, tt.taxonomy, tt.count FROM {$wpdb->term_taxonomy} tt
277 WHERE tt.taxonomy = %s AND tt.term_id > %d
278 AND ( tt.count > 0 OR EXISTS ( SELECT 1 FROM {$wpdb->term_taxonomy} child WHERE child.parent = tt.term_id AND child.taxonomy = tt.taxonomy ) )
279 ORDER BY tt.term_id ASC LIMIT %d",
280 $taxonomy,
281 (int) $after_id,
282 (int) $limit
283 ),
284 ARRAY_A
285 );
286
287 $rows = is_array( $rows ) ? $rows : [];
288
289 _prime_term_caches( array_map( 'intval', array_column( $rows, 'term_id' ) ), false );
290
291 return array_map(
292 function ( $row ) {
293 return [
294 'id' => (int) $row['term_id'],
295 'taxonomy' => $row['taxonomy'],
296 'count' => (int) $row['count'],
297 ];
298 },
299 $rows
300 );
301 }
302
303 /**
304 * {@inheritdoc}
305 */
306 public function term( $term_id ) {
307 $term = get_term( (int) $term_id );
308
309 return $term instanceof WP_Term ? $this->term_row( $term ) : null;
310 }
311
312 /**
313 * {@inheritdoc}
314 */
315 public function term_by_tt_id( $tt_id, $taxonomy ) {
316 $term = get_term_by( 'term_taxonomy_id', (int) $tt_id, $taxonomy );
317
318 return $term instanceof WP_Term ? $this->term_row( $term ) : null;
319 }
320
321 /**
322 * {@inheritdoc}
323 */
324 public function post_terms( $post_id ) {
325 $terms = wp_get_object_terms( (int) $post_id, $this->public_taxonomies() );
326
327 return is_array( $terms ) ? array_map( [ $this, 'term_row' ], $terms ) : [];
328 }
329
330 /**
331 * {@inheritdoc}
332 */
333 public function term_link( $term_id, $taxonomy ) {
334 return $this->link( get_term_link( (int) $term_id, $taxonomy ) );
335 }
336
337 /**
338 * {@inheritdoc}
339 */
340 public function term_has_children( $term_id, $taxonomy ) {
341 global $wpdb;
342
343 if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
344 return false;
345 }
346
347 return (bool) $wpdb->get_var(
348 $wpdb->prepare(
349 "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE parent = %d AND taxonomy = %s LIMIT 1",
350 (int) $term_id,
351 $taxonomy
352 )
353 );
354 }
355
356 /**
357 * {@inheritdoc}
358 */
359 public function object_in_taxonomy( $post_type, $taxonomy ) {
360 return is_object_in_taxonomy( $post_type, $taxonomy );
361 }
362
363 /**
364 * {@inheritdoc}
365 */
366 public function author_rows( $after_id, $limit ) {
367 global $wpdb;
368
369 $rows = $wpdb->get_results(
370 $wpdb->prepare(
371 "SELECT post_author, COUNT(*) AS total, MAX(post_modified_gmt) AS modified_gmt FROM {$wpdb->posts}
372 WHERE post_type = 'post' AND post_status = 'publish' AND post_author > %d
373 GROUP BY post_author ORDER BY post_author ASC LIMIT %d",
374 (int) $after_id,
375 (int) $limit
376 ),
377 ARRAY_A
378 );
379
380 $rows = is_array( $rows ) ? $rows : [];
381
382 cache_users( array_map( 'intval', array_column( $rows, 'post_author' ) ) );
383
384 return array_map(
385 function ( $row ) {
386 return [
387 'id' => (int) $row['post_author'],
388 'count' => (int) $row['total'],
389 'modified_gmt' => $row['modified_gmt'],
390 ];
391 },
392 $rows
393 );
394 }
395
396 /**
397 * {@inheritdoc}
398 */
399 public function author_post_count( $user_id ) {
400 return (int) count_user_posts( (int) $user_id, 'post', true );
401 }
402
403 /**
404 * {@inheritdoc}
405 */
406 public function author_link( $user_id ) {
407 if ( ! get_userdata( (int) $user_id ) ) {
408 return null;
409 }
410
411 return $this->link( get_author_posts_url( (int) $user_id ) );
412 }
413
414 /**
415 * {@inheritdoc}
416 */
417 public function month_rows( $before_key, $limit ) {
418 global $wpdb;
419
420 $before = $before_key > 0 ? sprintf( '%04d-%02d-01 00:00:00', intdiv( (int) $before_key, 100 ), (int) $before_key % 100 ) : '9999-12-31 23:59:59';
421 $rows = $wpdb->get_results(
422 $wpdb->prepare(
423 "SELECT DISTINCT YEAR(post_date) AS year, MONTH(post_date) AS month FROM {$wpdb->posts}
424 WHERE post_type = 'post' AND post_status = 'publish' AND post_date < %s
425 ORDER BY year DESC, month DESC LIMIT %d",
426 $before,
427 (int) $limit
428 ),
429 ARRAY_A
430 );
431
432 return array_map(
433 function ( $row ) {
434 return [
435 'year' => (int) $row['year'],
436 'month' => (int) $row['month'],
437 ];
438 },
439 is_array( $rows ) ? $rows : []
440 );
441 }
442
443 /**
444 * {@inheritdoc}
445 */
446 public function date_post_count( $year, $month ) {
447 global $wpdb;
448
449 $year = (int) $year;
450 $month = (int) $month;
451 $start = sprintf( '%04d-%02d-01 00:00:00', $year, $month > 0 ? $month : 1 );
452 $end = $month > 0
453 ? sprintf( '%04d-%02d-01 00:00:00', 12 === $month ? $year + 1 : $year, 12 === $month ? 1 : $month + 1 )
454 : sprintf( '%04d-01-01 00:00:00', $year + 1 );
455
456 return (int) $wpdb->get_var(
457 $wpdb->prepare(
458 "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' AND post_date >= %s AND post_date < %s",
459 $start,
460 $end
461 )
462 );
463 }
464
465 /**
466 * {@inheritdoc}
467 */
468 public function year_link( $year ) {
469 return get_year_link( (int) $year );
470 }
471
472 /**
473 * {@inheritdoc}
474 */
475 public function month_link( $year, $month ) {
476 return get_month_link( (int) $year, (int) $month );
477 }
478
479 /**
480 * {@inheritdoc}
481 */
482 public function feed_link( $feed = '' ) {
483 return get_feed_link( $feed );
484 }
485
486 /**
487 * {@inheritdoc}
488 */
489 public function paged_url( $base_url, $page ) {
490 global $wp_rewrite;
491
492 $pagination_base = $wp_rewrite instanceof WP_Rewrite ? $wp_rewrite->pagination_base : 'page';
493
494 return $this->pretty_url( $base_url, $pagination_base . '/' . (int) $page, 'paged', 'paged', $page );
495 }
496
497 /**
498 * {@inheritdoc}
499 */
500 public function comment( $comment_id ) {
501 $comment = get_comment( $comment_id );
502
503 if ( ! $comment ) {
504 return null;
505 }
506
507 return [
508 'post_id' => (int) $comment->comment_post_ID,
509 'approved' => (string) $comment->comment_approved,
510 ];
511 }
512
513 /**
514 * {@inheritdoc}
515 */
516 public function approved_comment_count( $post_id, $top_level_only ) {
517 $args = [
518 'post_id' => (int) $post_id,
519 'status' => 'approve',
520 'count' => true,
521 ];
522
523 if ( $top_level_only ) {
524 $args['parent'] = 0;
525 }
526
527 return (int) get_comments( $args );
528 }
529
530 /**
531 * {@inheritdoc}
532 */
533 public function comment_page_url( $permalink, $page ) {
534 global $wp_rewrite;
535
536 $base = $wp_rewrite instanceof WP_Rewrite ? $wp_rewrite->comments_pagination_base : 'comment-page';
537
538 return $this->pretty_url( $permalink, $base . '-' . (int) $page, 'commentpaged', 'cpage', $page );
539 }
540
541 /**
542 * {@inheritdoc}
543 */
544 public function attachment_file_url( $attachment_id ) {
545 return $this->link( wp_get_attachment_url( (int) $attachment_id ) );
546 }
547
548 /**
549 * {@inheritdoc}
550 */
551 public function attachment_metadata( $attachment_id ) {
552 $metadata = wp_get_attachment_metadata( (int) $attachment_id, true );
553
554 return is_array( $metadata ) ? $metadata : [];
555 }
556
557 /**
558 * {@inheritdoc}
559 */
560 public function sitemap_urls() {
561 $urls = [];
562
563 if ( function_exists( 'wp_sitemaps_get_server' ) ) {
564 $server = wp_sitemaps_get_server();
565
566 if ( $server->sitemaps_enabled() ) {
567 $urls[] = $server->index->get_index_url();
568 $urls[] = $server->renderer->get_sitemap_index_stylesheet_url();
569 $urls[] = $server->renderer->get_sitemap_stylesheet_url();
570
571 foreach ( $server->registry->get_providers() as $provider ) {
572 foreach ( $provider->get_sitemap_entries() as $entry ) {
573 $urls[] = $entry['loc'] ?? null;
574 }
575 }
576 }
577 }
578
579 $yoast_sitemap = defined( 'WPSEO_VERSION' ) && class_exists( 'WPSEO_Options' ) && \WPSEO_Options::get( 'enable_xml_sitemap' );
580 $rank_math_sitemap = class_exists( '\RankMath\Helper' ) && \RankMath\Helper::is_module_active( 'sitemap' );
581
582 if ( $yoast_sitemap || $rank_math_sitemap ) {
583 $urls[] = home_url( '/sitemap_index.xml' );
584 }
585
586 return $this->links( $urls );
587 }
588
589 /**
590 * {@inheritdoc}
591 */
592 public function site_icon_urls() {
593 if ( ! has_site_icon() ) {
594 return [];
595 }
596
597 return $this->links( [ get_site_icon_url( 32 ), get_site_icon_url( 180 ), get_site_icon_url( 192 ), get_site_icon_url( 270 ) ] );
598 }
599
600 /**
601 * {@inheritdoc}
602 */
603 public function theme_stylesheet_urls() {
604 $urls = [ get_stylesheet_uri() ];
605
606 if ( get_template() !== get_stylesheet() ) {
607 $urls[] = trailingslashit( get_template_directory_uri() ) . 'style.css';
608 }
609
610 return $this->links( $urls );
611 }
612
613 /**
614 * Add a page part to a URL: "/base/<suffix>/" with pretty permalinks, else "?<query_var>=<page>".
615 *
616 * @param string $base_url URL of page 1.
617 * @param string $suffix Path part for pretty permalinks.
618 * @param string $type Type for user_trailingslashit().
619 * @param string $query_var Query variable for plain permalinks.
620 * @param int $page Page number.
621 *
622 * @return string
623 */
624 private function pretty_url( $base_url, $suffix, $type, $query_var, $page ) {
625 global $wp_rewrite;
626
627 if ( ! $wp_rewrite instanceof WP_Rewrite || ! $wp_rewrite->using_permalinks() || false !== strpos( $base_url, '?' ) ) {
628 return add_query_arg( $query_var, (int) $page, $base_url );
629 }
630
631 return user_trailingslashit( trailingslashit( $base_url ) . $suffix, $type );
632 }
633
634 /**
635 * @param WP_Term $term Term.
636 *
637 * @return array{id:int, taxonomy:string, count:int}
638 */
639 private function term_row( WP_Term $term ) {
640 return [
641 'id' => (int) $term->term_id,
642 'taxonomy' => $term->taxonomy,
643 'count' => (int) $term->count,
644 ];
645 }
646
647 /**
648 * @param mixed $value Value from a WordPress link function.
649 *
650 * @return string|null
651 */
652 private function link( $value ) {
653 return is_string( $value ) && '' !== $value ? $value : null;
654 }
655
656 /**
657 * @param array $values Values from WordPress link functions.
658 *
659 * @return string[] Unique, not empty links.
660 */
661 private function links( array $values ) {
662 return array_values( array_unique( array_filter( array_map( [ $this, 'link' ], $values ) ) ) );
663 }
664
665 /**
666 * Remove objects of old batches from the runtime cache. Thus memory does not grow on big sites.
667 *
668 * @return void
669 */
670 private function flush_runtime_cache() {
671 if ( function_exists( 'wp_cache_supports' ) && wp_cache_supports( 'flush_runtime' ) ) {
672 wp_cache_flush_runtime();
673 }
674 }
675 }
676