PluginProbe
ActivityPub / 9.3.0
ActivityPub v9.3.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / integration / class-litespeed-cache.php

class-litespeed-cache.php in ActivityPub 9.3.0, at integration/class-litespeed-cache.php

234 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * LiteSpeed Cache integration file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Integration;
9
10 use function Activitypub\is_plugin_active;
11
12 /**
13 * LiteSpeed Cache integration.
14 *
15 * @see https://wordpress.org/support/topic/avoiding-caching-activitypub-content/
16 */
17 class Litespeed_Cache {
18
19 /**
20 * The rules to add to the htaccess file.
21 *
22 * @var string
23 */
24 public static $rules = '<IfModule LiteSpeed>
25 RewriteEngine On
26 RewriteCond %{HTTP:Accept} ^[\s,]*(application/activity\+json|application/ld\+json[^,]*activitystreams) [NC]
27 RewriteRule ^ - [E=Cache-Control:vary=%{ENV:LSCACHE_VARY_VALUE}+isjson]
28 </IfModule>';
29
30 /**
31 * The option name to store the htaccess rules.
32 *
33 * @var string
34 */
35 public static $option_name = 'activitypub_litespeed_cache_setup';
36
37 /**
38 * The marker to identify the rules in the htaccess file.
39 *
40 * @var string
41 */
42 public static $marker = 'ActivityPub LiteSpeed Cache';
43
44 /**
45 * The LiteSpeed Cache plugin slug.
46 *
47 * @var string
48 */
49 public static $plugin_slug = 'litespeed-cache/litespeed-cache.php';
50
51 /**
52 * Initialize the integration.
53 */
54 public static function init() {
55 // Add rules if LiteSpeed Cache is active and rules aren't set.
56 if ( is_plugin_active( self::$plugin_slug ) ) {
57 // (Re)write when the installed rules differ from the current ones: first setup, or a rules
58 // update that must replace a previously written (looser) block on existing installs.
59 if ( \get_option( self::$option_name ) !== \md5( self::$rules ) ) {
60 self::add_htaccess_rules();
61 }
62
63 \add_filter( 'site_status_tests', array( self::class, 'add_site_health_test' ) );
64
65 // Remove rules if LiteSpeed Cache is not active but rules were previously set.
66 } elseif ( \get_option( self::$option_name ) ) {
67 self::remove_htaccess_rules();
68 }
69
70 // Clean up when LiteSpeed Cache plugin is deleted.
71 \add_action( 'deleted_plugin', array( self::class, 'on_plugin_deleted' ) );
72 }
73
74 /**
75 * Clean up htaccess rules when LiteSpeed Cache plugin is deleted.
76 *
77 * @param string $plugin_file Path to the plugin file relative to the plugins directory.
78 */
79 public static function on_plugin_deleted( $plugin_file ) {
80 if ( self::$plugin_slug === $plugin_file && \get_option( self::$option_name ) ) {
81 self::remove_htaccess_rules();
82 }
83 }
84
85 /**
86 * Add the LiteSpeed Cache htaccess rules.
87 */
88 public static function add_htaccess_rules() {
89 $added_rules = self::append_with_markers( self::$marker, self::$rules );
90
91 // Store a fingerprint of the written rules so a later change re-applies them (see init()).
92 if ( $added_rules ) {
93 \update_option( self::$option_name, \md5( self::$rules ) );
94 } else {
95 \update_option( self::$option_name, '0' );
96 }
97 }
98
99 /**
100 * Remove the LiteSpeed Cache htaccess rules.
101 */
102 public static function remove_htaccess_rules() {
103 self::append_with_markers( self::$marker, '' );
104
105 \delete_option( self::$option_name );
106 }
107
108 /**
109 * Add the LiteSpeed Cache config test to site health.
110 *
111 * @param array $tests The site health tests.
112 *
113 * @return array The site health tests with the LiteSpeed Cache config test.
114 */
115 public static function add_site_health_test( $tests ) {
116 $tests['direct']['activitypub_test_litespeed_cache_integration'] = array(
117 'label' => \__( 'LiteSpeed Cache Test', 'activitypub' ),
118 'test' => array( self::class, 'test_litespeed_cache_integration' ),
119 );
120
121 return $tests;
122 }
123
124 /**
125 * Test the LiteSpeed Cache integration.
126 *
127 * @return array The test results.
128 */
129 public static function test_litespeed_cache_integration() {
130 $result = array(
131 'label' => \__( 'Compatibility with LiteSpeed Cache', 'activitypub' ),
132 'status' => 'good',
133 'badge' => array(
134 'label' => \__( 'ActivityPub', 'activitypub' ),
135 'color' => 'green',
136 ),
137 'description' => \sprintf(
138 '<p>%s</p>',
139 \__( 'LiteSpeed Cache is well configured to work with ActivityPub.', 'activitypub' )
140 ),
141 'actions' => '',
142 'test' => 'test_litespeed_cache_integration',
143 );
144
145 if ( ! \get_option( self::$option_name ) ) {
146 $result['status'] = 'critical';
147 $result['label'] = \__( 'LiteSpeed Cache might not be properly configured.', 'activitypub' );
148 $result['badge']['color'] = 'red';
149 $result['description'] = \sprintf(
150 '<p>%s</p>',
151 \__( 'LiteSpeed Cache isn&#8217;t currently set up to work with ActivityPub. While this isn&#8217;t a major problem, it&#8217;s a good idea to enable support. Without it, some technical files (like JSON) might accidentally show up in your website&#8217;s cache and be visible to visitors.', 'activitypub' )
152 );
153 $result['actions'] = \sprintf(
154 '<p>%s</p><pre>%s</pre>',
155 \__( 'To enable the ActivityPub integration with LiteSpeed Cache, add the following rules to your <code>.htaccess</code> file:', 'activitypub' ),
156 \esc_html( self::$rules )
157 );
158 }
159
160 return $result;
161 }
162
163 /**
164 * Prepend rules to the top of a file with markers.
165 *
166 * @param string $marker The marker to identify the rules in the file.
167 * @param string $rules The rules to prepend.
168 *
169 * @return bool True on success, false on failure.
170 */
171 private static function append_with_markers( $marker, $rules ) {
172 $htaccess_file = self::get_htaccess_file_path();
173
174 if ( ! \wp_is_writable( $htaccess_file ) ) {
175 return false;
176 }
177
178 // Ensure WP_Filesystem() is declared.
179 require_once ABSPATH . 'wp-admin/includes/file.php';
180
181 global $wp_filesystem;
182 \WP_Filesystem();
183
184 $htaccess = $wp_filesystem->get_contents( $htaccess_file );
185
186 // If marker exists, remove the old block first.
187 if ( \strpos( $htaccess, $marker ) !== false ) {
188 // Remove existing marker block.
189 $pattern = '/# BEGIN ' . \preg_quote( $marker, '/' ) . '.*?# END ' . \preg_quote( $marker, '/' ) . '\r?\n?/s';
190 $htaccess = \preg_replace( $pattern, '', $htaccess );
191 $htaccess = \trim( $htaccess );
192 }
193
194 // If rules are empty, just return (for removal case).
195 if ( empty( $rules ) ) {
196 return $wp_filesystem->put_contents( $htaccess_file, $htaccess, FS_CHMOD_FILE );
197 }
198
199 // Prepend new rules to the top of the file.
200 $start_marker = "# BEGIN {$marker}";
201 $end_marker = "# END {$marker}";
202
203 $rules = $start_marker . PHP_EOL . $rules . PHP_EOL . $end_marker;
204 $htaccess = $rules . PHP_EOL . PHP_EOL . $htaccess;
205
206 return $wp_filesystem->put_contents( $htaccess_file, $htaccess, FS_CHMOD_FILE );
207 }
208
209 /**
210 * Get the htaccess file.
211 *
212 * @return string|false The htaccess file or false.
213 */
214 private static function get_htaccess_file_path() {
215 $htaccess_file = false;
216
217 // Ensure get_home_path() is declared.
218 require_once ABSPATH . 'wp-admin/includes/file.php';
219
220 // phpcs:ignore WordPress.PHP.NoSilencedErrors
221 if ( @\file_exists( \get_home_path() . '.htaccess' ) ) {
222 /** The htaccess file resides in ABSPATH */
223 $htaccess_file = \get_home_path() . '.htaccess';
224 }
225
226 /**
227 * Filter the htaccess file path.
228 *
229 * @param string|false $htaccess_file The htaccess file path.
230 */
231 return \apply_filters( 'activitypub_litespeed_cache_htaccess_file', $htaccess_file );
232 }
233 }
234