litespeedtech / litespeedtech/lscache_wp

Purge::purge_url() returns void — callers cannot distinguish a purge from a silent rejection

Open Beginner friendly
#1,045 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
PHP
Stars
257
Forks
123
PR merge metrics
No merged PRs in 30d

Description

### Summary

`Purge::purge_url()` returns `void` and has three distinct paths that reject the request and return early. A caller has no way to distinguish "purged" from any of the three rejections, so integrations that expose purging to users report success on a guaranteed no-op.

### Detail

`src/purge.cls.php` in 7.9.1, `purge_url()` at line 943:

```php
public function purge_url( $url, $purge2 = false, $quite = false ) {
$val = trim( (string) $url );
if ( '' === $val ) {
return; // (1) empty — no debug line either
}

if ( false !== strpos( $val, '<' ) ) {
self::debug( "$val url contains <" ); // (2) angle bracket
return;
}

$val = Utility::make_relative( $val );
$hash = Tag::get_uri_tag( $val );

if ( false === $hash ) {
self::debug( "$val url invalid" ); // (3) tag lookup failed
return;
}

self::add( $hash, $purge2 );
...
do_action( 'litespeed_purged_link', $url );
}
```

All four exits — one success, three rejections — are `void`. Two of the rejections write a debug line, which is only visible when debug logging is on, and the first writes nothing at all.

### Why it matters

Any wrapper that offers "purge this URL" to a user or an API client has to report an outcome. With no return value the only options are to report unconditional success (wrong), mirror the vendor's validation rules in the wrapper (brittle — it silently stops matching the moment a fourth rule is added), or require debug logging and scrape the log (fragile, and the log format is internal).

We currently mirror the rules, which fails open: a new rejection path added upstream would not be inherited and we would resume reporting success on a no-op.

### Suggested fix

Return a value. `bool` would be enough:

```php
if ( false !== strpos( $val, '<' ) ) {
self::debug( "$val url contains <" );
return false;
}
...
do_action( 'litespeed_purged_link', $url );
return true;
```

This is backward compatible — existing callers ignore the return. A `WP_Error` carrying the reason would be even better, but a bool solves the reporting problem.

### Note

`do_action( 'litespeed_purged_link', $url )` already fires on the success path only, so a caller can partially infer the outcome by listening for it. That is a workaround rather than an interface, and it does not cover `purge_post`/`purge_all` style calls, but it does show the success signal already exists internally.

### Environment

- LiteSpeed Cache **7.9.1** (also present in 7.9 — `src/purge.cls.php` is byte-identical between the two)
- Verified by reading the shipped artifact from the wp.org ZIP, not from a running site

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in src/purge.cls.php at Purge::purge_url() around line 943 and inspect its four exit paths plus the existing litespeed_purged_link action. Check callers that use purge_url(), then verify that successful purges and each rejection are distinguishable while existing callers that ignore the return remain compatible.

Written by the indexing model from the issue text.

Assessment

Tech stack
php, wordpress
Domain
backend
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.