Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9f8462a
init
pfefferle May 9, 2025
204053e
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle May 13, 2025
c4672aa
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle May 13, 2025
d32ae58
simplify option key
pfefferle May 15, 2025
110b92c
ensure to add to the beginning of the file
pfefferle May 15, 2025
4f28033
styling
pfefferle May 15, 2025
3db8099
fix typo
pfefferle May 15, 2025
a928082
add tests
pfefferle May 15, 2025
fa30482
fix phpcs
pfefferle May 15, 2025
3df4796
fix check
pfefferle May 15, 2025
8592bc7
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Jun 19, 2025
5643b48
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Jun 20, 2025
a0edc31
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Jun 27, 2025
6a0c7e0
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Jul 24, 2025
73e3f4c
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 23, 2025
96f7881
Refactor Litespeed Cache integration and tests
pfefferle Oct 23, 2025
cc600df
Add plugin active check fallback utility
pfefferle Oct 23, 2025
0b16e7d
Standardize LiteSpeed Cache naming
pfefferle Oct 23, 2025
08eb4d9
Update integration/load.php
pfefferle Oct 23, 2025
232721e
Add changelog
matticbot Oct 23, 2025
83d5eb4
Rename is_plugin_active_with_fallback to is_plugin_active
pfefferle Oct 23, 2025
0144a4c
Add cleanup for LiteSpeed Cache htaccess rules
pfefferle Oct 23, 2025
58bcece
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 23, 2025
2dd1003
Remove LiteSpeed Cache htaccess cleanup on uninstall
pfefferle Oct 23, 2025
65caadd
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 23, 2025
dce7046
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 24, 2025
87c8852
Trigger deactivate action in cache test
pfefferle Oct 24, 2025
97a046b
LiteSpeed Cache integration suggestions (#2364)
obenland Oct 24, 2025
dc6155c
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 25, 2025
2cec515
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 27, 2025
b05cc26
Merge branch 'trunk' into integration/litespeed-cache-support
pfefferle Oct 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/changelog/1683-from-description
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add LiteSpeed Cache integration to prevent ActivityPub JSON responses from being cached incorrectly. Includes automatic .htaccess rules and Site Health check to ensure proper configuration.
20 changes: 20 additions & 0 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1828,3 +1828,23 @@ function get_url_authority( $url ) {

return $parsed['scheme'] . '://' . $parsed['host'];
}

/**
* Check if a plugin is active, loading plugin.php if necessary.
*
* This is a wrapper around the core is_plugin_active() function that ensures
* the function is available by loading wp-admin/includes/plugin.php if needed.
* This is useful when checking plugin status outside of the admin context.
*
* @param string $plugin Plugin basename (e.g., 'plugin-folder/plugin-file.php').
*
* @return bool True if the plugin is active, false otherwise.
*/
function is_plugin_active( $plugin ) {
// Include plugin.php if not already loaded (needed for core is_plugin_active).
if ( ! \function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

return \is_plugin_active( $plugin );
}
227 changes: 227 additions & 0 deletions integration/class-litespeed-cache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<?php
/**
* LiteSpeed Cache integration file.
*
* @package Activitypub
*/

namespace Activitypub\Integration;

use function Activitypub\is_plugin_active;

/**
* LiteSpeed Cache integration.
*
* @see https://wordpress.org/support/topic/avoiding-caching-activitypub-content/
*/
class Litespeed_Cache {

/**
* The rules to add to the htaccess file.
*
* @var string
*/
public static $rules = '<IfModule LiteSpeed>
RewriteEngine On
RewriteCond %{HTTP:Accept} application
RewriteRule ^ - [E=Cache-Control:vary=%{ENV:LSCACHE_VARY_VALUE}+isjson]
</IfModule>';

/**
* The option name to store the htaccess rules.
*
* @var string
*/
public static $option_name = 'activitypub_litespeed_cache_setup';

/**
* The marker to identify the rules in the htaccess file.
*
* @var string
*/
public static $marker = 'ActivityPub LiteSpeed Cache';

/**
* The LiteSpeed Cache plugin slug.
*
* @var string
*/
public static $plugin_slug = 'litespeed-cache/litespeed-cache.php';

/**
* Initialize the integration.
*/
public static function init() {
// Add rules if LiteSpeed Cache is active and rules aren't set.
if ( is_plugin_active( self::$plugin_slug ) ) {
if ( ! \get_option( self::$option_name ) ) {
self::add_htaccess_rules();
}

\add_filter( 'site_status_tests', array( self::class, 'add_site_health_test' ) );

// Remove rules if LiteSpeed Cache is not active but rules were previously set.
} elseif ( \get_option( self::$option_name ) ) {
self::remove_htaccess_rules();
}

// Clean up when LiteSpeed Cache plugin is deleted.
\add_action( 'deleted_plugin', array( self::class, 'on_plugin_deleted' ) );
}

/**
* Clean up htaccess rules when LiteSpeed Cache plugin is deleted.
*
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
*/
public static function on_plugin_deleted( $plugin_file ) {
if ( self::$plugin_slug === $plugin_file && \get_option( self::$option_name ) ) {
self::remove_htaccess_rules();
}
}

/**
* Add the LiteSpeed Cache htaccess rules.
*/
public static function add_htaccess_rules() {
$added_rules = self::append_with_markers( self::$marker, self::$rules );

if ( $added_rules ) {
\update_option( self::$option_name, '1' );
} else {
\update_option( self::$option_name, '0' );
}
}

/**
* Remove the LiteSpeed Cache htaccess rules.
*/
public static function remove_htaccess_rules() {
self::append_with_markers( self::$marker, '' );

\delete_option( self::$option_name );
}

/**
* Add the LiteSpeed Cache config test to site health.
*
* @param array $tests The site health tests.
*
* @return array The site health tests with the LiteSpeed Cache config test.
*/
public static function add_site_health_test( $tests ) {
$tests['direct']['activitypub_test_litespeed_cache_integration'] = array(
'label' => \__( 'LiteSpeed Cache Test', 'activitypub' ),
'test' => array( self::class, 'test_litespeed_cache_integration' ),
);

return $tests;
}

/**
* Test the LiteSpeed Cache integration.
*
* @return array The test results.
*/
public static function test_litespeed_cache_integration() {
$result = array(
'label' => \__( 'Compatibility with LiteSpeed Cache', 'activitypub' ),
'status' => 'good',
'badge' => array(
'label' => \__( 'ActivityPub', 'activitypub' ),
'color' => 'green',
),
'description' => \sprintf(
'<p>%s</p>',
\__( 'LiteSpeed Cache is well configured to work with ActivityPub.', 'activitypub' )
),
'actions' => '',
'test' => 'test_litespeed_cache_integration',
);

if ( ! \get_option( self::$option_name ) ) {
$result['status'] = 'critical';
$result['label'] = \__( 'LiteSpeed Cache might not be properly configured.', 'activitypub' );
$result['badge']['color'] = 'red';
$result['description'] = \sprintf(
'<p>%s</p>',
\__( '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' )
);
$result['actions'] = \sprintf(
'<p>%s</p><pre>%s</pre>',
\__( 'To enable the ActivityPub integration with LiteSpeed Cache, add the following rules to your <code>.htaccess</code> file:', 'activitypub' ),
\esc_html( self::$rules )
);
}

return $result;
}

/**
* Prepend rules to the top of a file with markers.
*
* @param string $marker The marker to identify the rules in the file.
* @param string $rules The rules to prepend.
*
* @return bool True on success, false on failure.
*/
private static function append_with_markers( $marker, $rules ) {
$htaccess_file = self::get_htaccess_file_path();

if ( ! \wp_is_writable( $htaccess_file ) ) {
return false;
}

// Ensure get_home_path() is declared.
require_once ABSPATH . 'wp-admin/includes/file.php';

global $wp_filesystem;
\WP_Filesystem();

$htaccess = $wp_filesystem->get_contents( $htaccess_file );

// If marker exists, remove the old block first.
if ( strpos( $htaccess, $marker ) !== false ) {
// Remove existing marker block.
$pattern = '/# BEGIN ' . preg_quote( $marker, '/' ) . '.*?# END ' . preg_quote( $marker, '/' ) . '\r?\n?/s';
$htaccess = preg_replace( $pattern, '', $htaccess );
$htaccess = trim( $htaccess );
}

// If rules are empty, just return (for removal case).
if ( empty( $rules ) ) {
return $wp_filesystem->put_contents( $htaccess_file, $htaccess, FS_CHMOD_FILE );
}

// Prepend new rules to the top of the file.
$start_marker = "# BEGIN {$marker}";
$end_marker = "# END {$marker}";

$rules = $start_marker . PHP_EOL . $rules . PHP_EOL . $end_marker;
$htaccess = $rules . PHP_EOL . PHP_EOL . $htaccess;

return $wp_filesystem->put_contents( $htaccess_file, $htaccess, FS_CHMOD_FILE );
}

/**
* Get the htaccess file.
*
* @return string|false The htaccess file or false.
*/
private static function get_htaccess_file_path() {
$htaccess_file = false;

// phpcs:ignore WordPress.PHP.NoSilencedErrors
if ( @file_exists( \get_home_path() . '.htaccess' ) ) {
/** The htaccess file resides in ABSPATH */
$htaccess_file = \get_home_path() . '.htaccess';
}

/**
* Filter the htaccess file path.
*
* @param string|false $htaccess_file The htaccess file path.
*/
return \apply_filters( 'activitypub_litespeed_cache_htaccess_file', $htaccess_file );
}
}
6 changes: 4 additions & 2 deletions integration/class-surge.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace Activitypub\Integration;

use function Activitypub\is_plugin_active;

/**
* Surge Cache integration.
*
Expand Down Expand Up @@ -38,7 +40,7 @@ public static function init() {
*/
public static function add_cache_config() {
// Check if surge is installed and active.
if ( ! \is_plugin_active( 'surge/surge.php' ) ) {
if ( ! is_plugin_active( 'surge/surge.php' ) ) {
return;
}

Expand Down Expand Up @@ -139,7 +141,7 @@ public static function get_config_file_path() {
* @return array The site health tests with the Surge cache config test.
*/
public static function maybe_add_site_health( $tests ) {
if ( ! \is_plugin_active( 'surge/surge.php' ) ) {
if ( ! is_plugin_active( 'surge/surge.php' ) ) {
return $tests;
}

Expand Down
14 changes: 14 additions & 0 deletions integration/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,27 @@ function ( $transformer, $data, $object_class ) {
* @see https://wordpress.org/plugins/surge/
*/
Surge::init();

/**
* Load the LiteSpeed Cache integration.
*
* The check for whether LiteSpeed Cache is loaded and initialized happens inside Litespeed_Cache::init().
*
* @see https://wordpress.org/plugins/litespeed-cache/
*/
Litespeed_Cache::init();
}
\add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' );

// Register activation and deactivation hooks for Surge integration.
\register_activation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\Surge', 'add_cache_config' ) );
\register_deactivation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\Surge', 'remove_cache_config' ) );

// Register activation and deactivation hooks for LiteSpeed Cache integration.
\register_activation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'add_htaccess_rules' ) );
\register_deactivation_hook( ACTIVITYPUB_PLUGIN_FILE, array( __NAMESPACE__ . '\LiteSpeed_Cache', 'remove_htaccess_rules' ) );


/**
* Register the Stream Connector for ActivityPub.
*
Expand Down
Loading