PluginProbe ʕ •ᴥ•ʔ
LiteSpeed Cache / 7.8.1
LiteSpeed Cache v7.8.1
trunk 1.0.15 1.9.1.1 2.9.9.2 3.6.4 4.6 5.7.0.1 6.5.4 7.0.0.1 7.0.1 7.1 7.2 7.3 7.3.0.1 7.4 7.5 7.5.0.1 7.6 7.6.1 7.6.2 7.7 7.8 7.8.0.1 7.8.1
litespeed-cache / src / tag.cls.php
litespeed-cache / src Last commit date
cdn 2 months ago data_structure 2 months ago activation.cls.php 2 months ago admin-display.cls.php 2 months ago admin-settings.cls.php 2 months ago admin.cls.php 2 months ago api.cls.php 2 months ago avatar.cls.php 2 months ago base.cls.php 2 months ago cdn.cls.php 2 months ago cloud-auth-callback.trait.php 2 months ago cloud-auth-ip.trait.php 2 months ago cloud-auth.trait.php 2 months ago cloud-misc.trait.php 2 months ago cloud-node.trait.php 2 months ago cloud-request.trait.php 2 months ago cloud.cls.php 2 months ago conf.cls.php 2 months ago control.cls.php 2 months ago core.cls.php 2 months ago crawler-map.cls.php 2 months ago crawler.cls.php 2 months ago css.cls.php 2 months ago data.cls.php 2 months ago data.upgrade.func.php 2 months ago db-optm.cls.php 2 months ago debug2.cls.php 2 months ago doc.cls.php 2 months ago error.cls.php 2 months ago esi.cls.php 2 months ago file.cls.php 2 months ago guest.cls.php 2 months ago gui.cls.php 2 months ago health.cls.php 2 months ago htaccess.cls.php 2 months ago img-optm-manage.trait.php 2 months ago img-optm-pull.trait.php 2 months ago img-optm-send.trait.php 2 months ago img-optm.cls.php 2 months ago import.cls.php 2 months ago import.preset.cls.php 2 months ago lang.cls.php 2 months ago localization.cls.php 2 months ago media.cls.php 2 months ago metabox.cls.php 2 months ago object-cache-wp.cls.php 2 months ago object-cache.cls.php 2 months ago object.lib.php 2 months ago optimize.cls.php 2 months ago optimizer.cls.php 2 months ago placeholder.cls.php 2 months ago purge.cls.php 2 months ago report.cls.php 2 months ago rest.cls.php 2 months ago root.cls.php 2 months ago router.cls.php 2 months ago str.cls.php 2 months ago tag.cls.php 2 months ago task.cls.php 2 months ago tool.cls.php 2 months ago ucss.cls.php 2 months ago utility.cls.php 2 months ago vary.cls.php 2 months ago vpi.cls.php 2 months ago
tag.cls.php
380 lines
1 <?php
2 // phpcs:ignoreFile
3
4 /**
5 * The plugin cache-tag class for X-LiteSpeed-Tag
6 *
7 * @since 1.1.3
8 */
9
10 namespace LiteSpeed;
11
12 defined('WPINC') || exit();
13
14 class Tag extends Root {
15
16 const TYPE_FEED = 'FD';
17 const TYPE_FRONTPAGE = 'F';
18 const TYPE_HOME = 'H';
19 const TYPE_PAGES = 'PGS';
20 const TYPE_PAGES_WITH_RECENT_POSTS = 'PGSRP';
21 const TYPE_HTTP = 'HTTP.';
22 const TYPE_POST = 'Po.'; // Post. Cannot use P, reserved for litemage.
23 const TYPE_ARCHIVE_POSTTYPE = 'PT.';
24 const TYPE_ARCHIVE_TERM = 'T.'; // for is_category|is_tag|is_tax
25 const TYPE_AUTHOR = 'A.';
26 const TYPE_ARCHIVE_DATE = 'D.';
27 const TYPE_BLOG = 'B.';
28 const TYPE_LOGIN = 'L';
29 const TYPE_URL = 'URL.';
30 const TYPE_WIDGET = 'W.';
31 const TYPE_ESI = 'ESI.';
32 const TYPE_REST = 'REST';
33 const TYPE_AJAX = 'AJAX.';
34 const TYPE_LIST = 'LIST';
35 const TYPE_MIN = 'MIN';
36 const TYPE_LOCALRES = 'LOCALRES';
37
38 const X_HEADER = 'X-LiteSpeed-Tag';
39
40 private static $_tags = array();
41 private static $_tags_priv = array( 'tag_priv' );
42 public static $error_code_tags = array( 403, 404, 500 );
43
44 /**
45 * Initialize
46 *
47 * @since 4.0
48 */
49 public function init() {
50 // register recent posts widget tag before theme renders it to make it work
51 add_filter('widget_posts_args', array( $this, 'add_widget_recent_posts' ));
52 }
53
54 /**
55 * Check if the login page is cacheable.
56 * If not, unset the cacheable member variable.
57 *
58 * NOTE: This is checked separately because login page doesn't go through WP logic.
59 *
60 * @since 1.0.0
61 * @access public
62 */
63 public function check_login_cacheable() {
64 if (!$this->conf(Base::O_CACHE_PAGE_LOGIN)) {
65 return;
66 }
67 if (Control::isset_notcacheable()) {
68 return;
69 }
70
71 if (!empty($_GET)) {
72 Control::set_nocache('has GET request');
73 return;
74 }
75
76 $this->cls('Control')->set_cacheable();
77
78 self::add(self::TYPE_LOGIN);
79
80 // we need to send lsc-cookie manually to make it be sent to all other users when is cacheable
81 $list = headers_list();
82 if (empty($list)) {
83 return;
84 }
85 foreach ($list as $hdr) {
86 if (strncasecmp($hdr, 'set-cookie:', 11) == 0) {
87 $cookie = substr($hdr, 12);
88 @header('lsc-cookie: ' . $cookie, false);
89 }
90 }
91 }
92
93 /**
94 * Register purge tag for pages with recent posts widget
95 * of the plugin.
96 *
97 * @since 1.0.15
98 * @access public
99 * @param array $params [WordPress params for widget_posts_args]
100 */
101 public function add_widget_recent_posts( $params ) {
102 self::add(self::TYPE_PAGES_WITH_RECENT_POSTS);
103 return $params;
104 }
105
106 /**
107 * Adds cache tags to the list of cache tags for the current page.
108 *
109 * @since 1.0.5
110 * @access public
111 * @param mixed $tags A string or array of cache tags to add to the current list.
112 */
113 public static function add( $tags ) {
114 if (!is_array($tags)) {
115 $tags = array( $tags );
116 }
117
118 Debug2::debug('💰 [Tag] Add ', $tags);
119
120 self::$_tags = array_merge(self::$_tags, $tags);
121
122 // Send purge header immediately
123 $tag_header = self::cls()->output(true);
124 @header($tag_header);
125 }
126
127 /**
128 * Add a post id to cache tag
129 *
130 * @since 3.0
131 * @access public
132 */
133 public static function add_post( $pid ) {
134 self::add(self::TYPE_POST . $pid);
135 }
136
137 /**
138 * Add a widget id to cache tag
139 *
140 * @since 3.0
141 * @access public
142 */
143 public static function add_widget( $id ) {
144 self::add(self::TYPE_WIDGET . $id);
145 }
146
147 /**
148 * Add a private ESI to cache tag
149 *
150 * @since 3.0
151 * @access public
152 */
153 public static function add_private_esi( $tag ) {
154 self::add_private(self::TYPE_ESI . $tag);
155 }
156
157 /**
158 * Adds private cache tags to the list of cache tags for the current page.
159 *
160 * @since 1.6.3
161 * @access public
162 * @param mixed $tags A string or array of cache tags to add to the current list.
163 */
164 public static function add_private( $tags ) {
165 if (!is_array($tags)) {
166 $tags = array( $tags );
167 }
168
169 self::$_tags_priv = array_merge(self::$_tags_priv, $tags);
170 }
171
172 /**
173 * Return tags for Admin QS
174 *
175 * @since 1.1.3
176 * @access public
177 */
178 public static function output_tags() {
179 return self::$_tags;
180 }
181
182 /**
183 * Will get a hash of the URI. Removes query string and appends a '/' if it is missing.
184 *
185 * @since 1.0.12
186 * @access public
187 * @param string $uri The uri to get the hash of.
188 * @param boolean $ori Return the original url or not
189 * @return bool|string False on input error, hash otherwise.
190 */
191 public static function get_uri_tag( $uri, $ori = false ) {
192 $no_qs = strtok($uri, '?');
193 if (empty($no_qs)) {
194 return false;
195 }
196 $slashed = trailingslashit($no_qs);
197
198 // If only needs uri tag
199 if ($ori) {
200 return $slashed;
201 }
202
203 if (defined('LSCWP_LOG')) {
204 return self::TYPE_URL . $slashed;
205 }
206 return self::TYPE_URL . md5($slashed);
207 }
208
209 /**
210 * Get the unique tag based on self url.
211 *
212 * @since 1.1.3
213 * @access public
214 * @param boolean $ori Return the original url or not
215 */
216 public static function build_uri_tag( $ori = false ) {
217 return self::get_uri_tag(urldecode($_SERVER['REQUEST_URI']), $ori);
218 }
219
220 /**
221 * Gets the cache tags to set for the page.
222 *
223 * This includes site wide post types (e.g. front page) as well as
224 * any third party plugin specific cache tags.
225 *
226 * @since 1.0.0
227 * @access private
228 * @return array The list of cache tags to set.
229 */
230 private static function _build_type_tags() {
231 $tags = array();
232
233 $tags[] = Utility::page_type();
234
235 $tags[] = self::build_uri_tag();
236
237 if (is_front_page()) {
238 $tags[] = self::TYPE_FRONTPAGE;
239 } elseif (is_home()) {
240 $tags[] = self::TYPE_HOME;
241 }
242
243 global $wp_query;
244 if (isset($wp_query)) {
245 $queried_obj_id = get_queried_object_id();
246 if (is_archive()) {
247 // An Archive is a Category, Tag, Author, Date, Custom Post Type or Custom Taxonomy based pages.
248 if (is_category() || is_tag() || is_tax()) {
249 $tags[] = self::TYPE_ARCHIVE_TERM . $queried_obj_id;
250 } elseif (is_post_type_archive() && ($post_type = get_post_type())) {
251 $tags[] = self::TYPE_ARCHIVE_POSTTYPE . $post_type;
252 } elseif (is_author()) {
253 $tags[] = self::TYPE_AUTHOR . $queried_obj_id;
254 } elseif (is_date()) {
255 global $post;
256
257 if ($post && isset($post->post_date)) {
258 $date = $post->post_date;
259 $date = strtotime($date);
260 if (is_day()) {
261 $tags[] = self::TYPE_ARCHIVE_DATE . date('Ymd', $date);
262 } elseif (is_month()) {
263 $tags[] = self::TYPE_ARCHIVE_DATE . date('Ym', $date);
264 } elseif (is_year()) {
265 $tags[] = self::TYPE_ARCHIVE_DATE . date('Y', $date);
266 }
267 }
268 }
269 } elseif (is_singular()) {
270 // $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
271 $tags[] = self::TYPE_POST . $queried_obj_id;
272
273 if (is_page()) {
274 $tags[] = self::TYPE_PAGES;
275 }
276 } elseif (is_feed()) {
277 $tags[] = self::TYPE_FEED;
278 }
279 }
280
281 // Check REST API
282 if (REST::cls()->is_rest()) {
283 $tags[] = self::TYPE_REST;
284
285 $path = !empty($_SERVER['SCRIPT_URL']) ? $_SERVER['SCRIPT_URL'] : false;
286 if ($path) {
287 // posts collections tag
288 if (substr($path, -6) == '/posts') {
289 $tags[] = self::TYPE_LIST; // Not used for purge yet
290 }
291
292 // single post tag
293 global $post;
294 if (!empty($post->ID) && substr($path, -strlen($post->ID) - 1) === '/' . $post->ID) {
295 $tags[] = self::TYPE_POST . $post->ID;
296 }
297
298 // pages collections & single page tag
299 if (stripos($path, '/pages') !== false) {
300 $tags[] = self::TYPE_PAGES;
301 }
302 }
303 }
304
305 // Append AJAX action tag
306 if (Router::is_ajax() && !empty($_REQUEST['action'])) {
307 $tags[] = self::TYPE_AJAX . $_REQUEST['action'];
308 }
309
310 return $tags;
311 }
312
313 /**
314 * Generate all cache tags before output
315 *
316 * @access private
317 * @since 1.1.3
318 */
319 private static function _finalize() {
320 // run 3rdparty hooks to tag
321 do_action('litespeed_tag_finalize');
322 // generate wp tags
323 if (!defined('LSCACHE_IS_ESI')) {
324 $type_tags = self::_build_type_tags();
325 self::$_tags = array_merge(self::$_tags, $type_tags);
326 }
327
328 if (defined('LITESPEED_GUEST') && LITESPEED_GUEST) {
329 self::$_tags[] = 'guest';
330 }
331
332 // append blog main tag
333 self::$_tags[] = '';
334 // removed duplicates
335 self::$_tags = array_unique(self::$_tags);
336 }
337
338 /**
339 * Sets up the Cache Tags header.
340 * ONLY need to run this if is cacheable
341 *
342 * @since 1.1.3
343 * @access public
344 * @return string empty string if empty, otherwise the cache tags header.
345 */
346 public function output( $no_finalize = false ) {
347 if (defined('LSCACHE_NO_CACHE') && LSCACHE_NO_CACHE) {
348 return;
349 }
350
351 if (!$no_finalize) {
352 self::_finalize();
353 }
354
355 $prefix_tags = array();
356 /**
357 * Only append blog_id when is multisite
358 *
359 * @since 2.9.3
360 */
361 $prefix = LSWCP_TAG_PREFIX . (is_multisite() ? get_current_blog_id() : '') . '_';
362
363 // If is_private and has private tags, append them first, then specify prefix to `public` for public tags
364 if (Control::is_private()) {
365 foreach (self::$_tags_priv as $priv_tag) {
366 $prefix_tags[] = $prefix . $priv_tag;
367 }
368 $prefix = 'public:' . $prefix;
369 }
370
371 foreach (self::$_tags as $tag) {
372 $prefix_tags[] = $prefix . $tag;
373 }
374
375 $hdr = self::X_HEADER . ': ' . implode(',', $prefix_tags);
376
377 return $hdr;
378 }
379 }
380