PluginProbe
Docket Cache – Object Cache Accelerator / 22.07.05
Docket Cache – Object Cache Accelerator v22.07.05
26.04.05 trunk 22.07.01 22.07.02 22.07.03 22.07.04 22.07.05 23.08.01 23.08.02 24.07.01 24.07.02 24.07.03 24.07.04 24.07.05 24.07.06 24.07.07 26.04.03 26.04.04
docket-cache / includes / src / PostCache.php

PostCache.php in Docket Cache – Object Cache Accelerator 22.07.05, at includes/src/PostCache.php

281 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Docket Cache.
4 *
5 * @author Nawawi Jamili
6 * @license MIT
7 *
8 * @see https://github.com/nawawi/docket-cache
9 */
10
11 namespace Nawawi\DocketCache;
12
13 \defined('ABSPATH') || exit;
14
15 #[AllowDynamicProperties]
16 final class PostCache
17 {
18 public $prefix = 'docketcache-post';
19 public $group_prefix;
20 public $cache_incr = 0;
21 public $cache_group = '';
22 public $cache_key = '';
23 public $all_post_ids = false;
24 public $cached_post_ids = [];
25 public $cached_posts = [];
26 public $found_posts = false;
27 public $cache_func = 'wp_cache_add';
28 public $cache_func_expiry = 86400; // 1d
29 public $allow_posttype = [];
30 public $blacklist_posttype = [];
31 public $allow_posttype_all = false;
32
33 public function __construct()
34 {
35 $this->group_prefix = $this->prefix.'-';
36 $this->allow_posttype = [
37 'post',
38 'page',
39 'attachment',
40 'revision',
41 'nav_menu_item',
42 'custom_css',
43 'customize_changeset',
44 'oembed_cache',
45 'user_request',
46 'wp_block',
47 'wp_template',
48 'wp_template_part',
49 'wp_global_styles',
50 'wp_navigation',
51 ];
52
53 $this->blacklist_posttype = ['scheduled-action'];
54 }
55
56 public function register()
57 {
58 // already in core.
59 // https://github.com/WordPress/wordpress-develop/commit/7f7d616d822b79c952cbd6a3046a6f6a8aa5a35e
60 if (isset($GLOBALS['wp_version']) && version_compare($GLOBALS['wp_version'], '6.1', '<')) {
61 $this->allow_posttype_all = nwdcx_construe('ADVCPOST_POSTTYPE_ALL');
62 if (!$this->allow_posttype_all) {
63 $types = nwdcx_constval('ADVCPOST_POSTTYPE');
64
65 if (\is_string($types) && 'all' === $types || \in_array($types, $this->allow_posttype)) {
66 $this->allow_posttype = $types;
67 } elseif (!empty($types) && \is_array($types)) {
68 $this->allow_posttype = array_merge($this->allow_posttype, $types);
69 }
70 }
71
72 $this->setup_for_blog();
73
74 add_action('switch_blog', [$this, 'setup_for_blog'], 10, 2);
75 add_filter('posts_request', [&$this, 'posts_request'], 10, 2);
76 add_filter('posts_results', [&$this, 'posts_results'], 10, 2);
77 add_filter('post_limits_request', [&$this, 'post_limits_request'], 999, 2);
78 add_filter('found_posts_query', [&$this, 'found_posts_query'], 10, 2);
79 add_filter('found_posts', [&$this, 'found_posts'], 10, 2);
80
81 add_action('clean_term_cache', [$this, 'invalidate_cache']);
82 add_action('clean_post_cache', [$this, 'invalidate_cache']);
83
84 add_action('added_post_meta', [$this, 'invalidate_cache']);
85 add_action('updated_post_meta', [$this, 'invalidate_cache']);
86 add_action('deleted_post_meta', [$this, 'invalidate_cache']);
87 }
88 }
89
90 public function setup_for_blog($new_blog_id = false, $previous_blog_id = false)
91 {
92 if ($new_blog_id && $new_blog_id === $previous_blog_id) {
93 return;
94 }
95
96 $this->cache_incr = wp_cache_get('cache_incr', $this->prefix);
97 if (!is_numeric($this->cache_incr)) {
98 $now = time();
99 wp_cache_set('cache_incr', $now, $this->prefix);
100 $this->cache_incr = $now;
101 }
102 $this->cache_group = $this->group_prefix.$this->cache_incr;
103 }
104
105 public function invalidate_cache()
106 {
107 if (is_admin() && isset($_POST['wp-preview']) && 'dopreview' === $_POST['wp-preview']) {
108 return;
109 }
110
111 if (\defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
112 return;
113 }
114
115 $this->cache_incr = wp_cache_incr('cache_incr', 1, $this->prefix);
116
117 if (10 < \strlen($this->cache_incr)) {
118 wp_cache_set('cache_incr', 0, $this->prefix);
119 $this->cache_incr = 0;
120 }
121 $this->cache_group = $this->group_prefix.$this->cache_incr;
122 }
123
124 private function allow_post_type($post_type)
125 {
126 if ($this->allow_posttype_all && !\in_array($post_type, $this->blacklist_posttype)) {
127 return true;
128 }
129
130 $this->allow_posttype = apply_filters('docketcache/filter/postcache/posttype', $this->allow_posttype);
131 if (\is_string($this->allow_posttype) && ('all' === $this->allow_posttype || $post_type === $this->allow_posttype)) {
132 return true;
133 }
134
135 if (\in_array($post_type, $this->allow_posttype) || \in_array('all', $this->allow_posttype)) {
136 return true;
137 }
138
139 return false;
140 }
141
142 public function posts_request($sql, $query)
143 {
144 if (!nwdcx_wpdb($wpdb)) {
145 return $sql;
146 }
147
148 $post_type = $query->get('post_type');
149 if (!$this->allow_post_type($post_type)) {
150 return $sql;
151 }
152
153 $this->cache_key = 'query-'.$post_type.'-'.md5($sql);
154 $this->all_post_ids = wp_cache_get($this->cache_key, $this->cache_group);
155
156 if ('NA' !== $this->found_posts) {
157 $cache_key = $this->cache_key.'-found';
158 $this->found_posts = wp_cache_get($cache_key, $this->cache_group);
159 }
160
161 if ($this->all_post_ids xor $this->found_posts) {
162 $this->cache_func = 'wp_cache_set';
163 } else {
164 $this->cache_func = 'wp_cache_add';
165 }
166
167 $this->cached_post_ids = [];
168 $this->cached_posts = [];
169
170 if ($this->found_posts && \is_array($this->all_post_ids)) {
171 if (\function_exists('wp_cache_get_multi')) {
172 $this->cached_posts = wp_cache_get_multi(['posts' => $this->all_post_ids]);
173 } else {
174 $this->cached_posts = [];
175 foreach ($this->all_post_ids as $key) {
176 $this->cached_posts[$key] = wp_cache_get($key, 'posts');
177 }
178 }
179
180 // array_filter = remove "empty" array
181 $this->cached_posts = array_filter($this->cached_posts);
182
183 foreach ($this->cached_posts as $post) {
184 if (!empty($post)) {
185 $this->cached_post_ids[] = $post->ID;
186 }
187 }
188 $uncached_post_ids = array_diff($this->all_post_ids, $this->cached_post_ids);
189
190 if ($uncached_post_ids) {
191 return "SELECT * FROM `{$wpdb->posts}` WHERE ID IN(".implode(',', array_map('absint', $uncached_post_ids)).')';
192 }
193
194 return '';
195 }
196
197 return $sql;
198 }
199
200 public function posts_results($posts, $query)
201 {
202 if (!$this->allow_post_type($query->get('post_type'))) {
203 return $posts;
204 }
205
206 if ($this->found_posts && \is_array($this->all_post_ids)) {
207 $collated_posts = [];
208 foreach ($this->cached_posts as $post) {
209 $posts[] = $post;
210 }
211
212 foreach ($posts as $post) {
213 $loc = array_search($post->ID, $this->all_post_ids);
214 if (is_numeric($loc) && -1 < $loc) {
215 $collated_posts[$loc] = $post;
216 }
217 }
218 ksort($collated_posts);
219
220 return array_map('get_post', array_values($collated_posts));
221 }
222
223 $post_ids = [];
224 foreach ((array) $posts as $post) {
225 $post_ids[] = $post->ID;
226 }
227
228 if (!$post_ids) {
229 return [];
230 }
231
232 \call_user_func($this->cache_func, $this->cache_key, $post_ids, $this->cache_group, $this->cache_func_expiry);
233
234 return array_map('get_post', $posts);
235 }
236
237 public function post_limits_request($limits, $query)
238 {
239 if (!$this->allow_post_type($query->get('post_type'))) {
240 return $limits;
241 }
242
243 if (empty($limits) || (isset($query->query_vars['no_found_rows']) && $query->query_vars['no_found_rows'])) {
244 $this->found_posts = 'NA';
245 } else {
246 $this->found_posts = false;
247 }
248
249 return $limits;
250 }
251
252 public function found_posts_query($sql, $query)
253 {
254 if (!$this->allow_post_type($query->get('post_type'))) {
255 return $sql;
256 }
257
258 if ($this->found_posts && \is_array($this->all_post_ids)) {
259 return '';
260 }
261
262 return $sql;
263 }
264
265 public function found_posts($found_posts, $query)
266 {
267 if (!$this->allow_post_type($query->get('post_type'))) {
268 return $found_posts;
269 }
270
271 if ($this->found_posts && \is_array($this->all_post_ids)) {
272 return (int) $this->found_posts;
273 }
274
275 $cache_key = $this->cache_key.'-found';
276 \call_user_func($this->cache_func, $cache_key, (int) $found_posts, $this->cache_group, $this->cache_func_expiry);
277
278 return $found_posts;
279 }
280 }
281