PluginProbe
WindPress – Tailwind CSS integration for WordPress / 3.2.89
WindPress – Tailwind CSS integration for WordPress v3.2.89
3.2.89 3.2.88 3.2.87 3.2.86 3.2.85 3.2.84 3.2.83 3.2.82 3.2.81 trunk 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.13 3.0.14 3.0.15 3.0.16 3.0.17 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 All 143 releases
windpress / src / Core / Scanner / PostQuery.php

PostQuery.php in WindPress – Tailwind CSS integration for WordPress 3.2.89, at src/Core/Scanner/PostQuery.php

94 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare (strict_types=1);
4 namespace WindPress\WindPress\Core\Scanner;
5
6 use InvalidArgumentException;
7 use WP_Query;
8 /**
9 * A bounded, ID-ordered scan of posts. Numeric pages remain accepted for older callers.
10 */
11 class PostQuery
12 {
13 public WP_Query $query;
14 private int $maximum_id;
15 private int $batch_size;
16 private int $after_id = 0;
17 private int $page = 1;
18 private string $signature;
19 public function __construct(array $arguments, array $metadata = [])
20 {
21 global $wpdb;
22 $this->batch_size = self::batch_size($arguments['posts_per_page'] ?? null);
23 $this->signature = hash('sha256', wp_json_encode($arguments));
24 $cursor = $metadata['next_batch'] ?? \false;
25 if (is_string($cursor) && strpos($cursor, 'posts:') === 0) {
26 $state = json_decode((string) base64_decode(substr($cursor, 6), \true), \true);
27 if (!is_array($state) || ($state['query'] ?? null) !== $this->signature || !isset($state['after'], $state['max'], $state['size']) || !is_int($state['after']) || !is_int($state['max']) || !is_int($state['size']) || $state['after'] < 0 || $state['max'] < $state['after'] || $state['size'] < 1 || $state['size'] > 200) {
28 throw new InvalidArgumentException(__('The post scan cursor is invalid. Restart the scan.', 'windpress'));
29 }
30 $this->after_id = $state['after'];
31 $this->maximum_id = $state['max'];
32 $this->batch_size = $state['size'];
33 } else {
34 if ($cursor !== \false && $cursor !== null) {
35 if (!is_int($cursor) && !is_string($cursor) || !ctype_digit((string) $cursor) || (int) $cursor < 1) {
36 throw new InvalidArgumentException(__('The post scan page is invalid.', 'windpress'));
37 }
38 $this->page = (int) $cursor;
39 }
40 $this->maximum_id = (int) $wpdb->get_var("SELECT MAX(ID) FROM {$wpdb->posts}");
41 if ($wpdb->last_error !== '') {
42 throw new \RuntimeException(__('Unable to initialize the post scan.', 'windpress'));
43 }
44 }
45 $arguments = array_merge($arguments, ['windpress_scan' => \true, 'posts_per_page' => $this->batch_size, 'paged' => $this->page, 'orderby' => 'ID', 'order' => 'ASC', 'no_found_rows' => \true, 'ignore_sticky_posts' => \true, 'suppress_filters' => \false]);
46 $this->query = new WP_Query();
47 $where_filter = function (string $where, WP_Query $query) use ($wpdb): string {
48 if ($query !== $this->query) {
49 return $where;
50 }
51 return $where . $wpdb->prepare(" AND {$wpdb->posts}.ID > %d AND {$wpdb->posts}.ID <= %d", $this->after_id, $this->maximum_id);
52 };
53 add_filter('posts_where', $where_filter, 10, 2);
54 try {
55 $wpdb->last_error = '';
56 $this->query->query($arguments);
57 if ($wpdb->last_error !== '') {
58 throw new \RuntimeException(__('Unable to read a post scan batch.', 'windpress'));
59 }
60 if ((int) $this->query->query_vars['posts_per_page'] !== $this->batch_size || (int) ($this->query->query_vars['offset'] ?? 0) !== 0 || count($this->query->posts) > $this->batch_size) {
61 throw new \RuntimeException(__('A query filter changed the scan batch limits. Exclude WindPress scans from that filter.', 'windpress'));
62 }
63 $previous_id = $this->after_id;
64 foreach ($this->query->posts as $post) {
65 $post_id = is_object($post) ? (int) $post->ID : (int) $post;
66 if ($post_id <= $previous_id || $post_id > $this->maximum_id) {
67 throw new \RuntimeException(__('A query filter changed the scan ordering. Exclude WindPress scans from that filter.', 'windpress'));
68 }
69 $previous_id = $post_id;
70 }
71 } finally {
72 remove_filter('posts_where', $where_filter, 10);
73 }
74 }
75 public static function batch_size($value = null): int
76 {
77 $default = (int) apply_filters('f!windpress/core/scanner:batch_size', 50);
78 $value = is_numeric($value) && (int) $value > 0 ? (int) $value : $default;
79 return max(1, min(200, $value));
80 }
81 public function is_first_batch(): bool
82 {
83 return $this->after_id === 0 && $this->page === 1;
84 }
85 public function metadata(): array
86 {
87 $posts = $this->query->posts;
88 $last_post = $posts === [] ? null : end($posts);
89 $last_id = is_object($last_post) ? (int) $last_post->ID : (int) $last_post;
90 $has_more = count($posts) === $this->batch_size && $last_id > $this->after_id && $last_id < $this->maximum_id;
91 return ['next_batch' => $has_more ? 'posts:' . base64_encode(wp_json_encode(['after' => $last_id, 'max' => $this->maximum_id, 'size' => $this->batch_size, 'query' => $this->signature])) : \false, 'total_batches' => \false];
92 }
93 }
94