Skip to content

Pr 357#359

Open
superdav42 wants to merge 4 commits intomainfrom
pr-357
Open

Pr 357#359
superdav42 wants to merge 4 commits intomainfrom
pr-357

Conversation

@superdav42
Copy link
Collaborator

@superdav42 superdav42 commented Mar 7, 2026

Summary by CodeRabbit

  • Refactor

    • Replaced external caching dependency with WordPress-native transient-based caching for improved compatibility and reduced external dependencies.
    • Enhanced code quality with explicit return type declarations.
  • Tests

    • Added comprehensive unit and integration test coverage for caching functionality.

superdav42 and others added 4 commits March 5, 2026 16:04
…n for SSO

This commit resolves a fatal error caused by incompatibility between
symfony/cache v5.4 and psr/simple-cache v3.0+.

Changes:
- Add WordPress_Simple_Cache class implementing PSR-16 CacheInterface
  using WordPress transients (get_site_transient, set_site_transient)
- Update SSO class to use WordPress_Simple_Cache instead of symfony/cache
- Remove symfony/cache dependency from composer.json (reduces 3 packages)
- Add comprehensive unit tests for WordPress_Simple_Cache
- Add standalone integration tests for PSR-16 compliance

Benefits:
- Eliminates PSR-16 compatibility error in SSO functionality
- Reduces dependency footprint (removed symfony/cache, symfony/cache-contracts, symfony/var-exporter)
- Better WordPress integration using native transient APIs
- Maintains full PSR-16 compatibility required by jasny/sso library

Fixes: Fatal Error 'psr/simple-cache 3.0+ is not compatible with symfony/cache v5.4'

Note: PHPCS warnings about 'default' parameter name and direct database
calls are acceptable as they follow PSR-16 standard and are necessary
for cache clearing functionality.
…e implementation bugs

- Add missing patches/mpdf-psr-http-message-shim-php8-compat.patch (file was
  referenced in composer.json but not committed, causing composer install to fail
  on all PHP versions with a TypeError in cweagans/composer-patches)
- Restore hashids/hashids to composer.json (was removed but still required by
  inc/helpers/class-hash.php — would cause fatal class-not-found in production)
- Fix WordPress_Simple_Cache::get/set to wrap values in array so that storing
  false can be distinguished from a cache miss (get_site_transient returns false
  for both missing keys and stored false values)
- Fix WordPress_Simple_Cache::clear() to use delete_site_transient() which
  properly clears the WordPress object cache, not just the DB rows (direct DB
  delete left stale values in the in-memory cache, causing test failures)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merge changes from main (PRs #352 mpdf PHP8.5 compat, #355 lazy settings,
#358 remove hashids dependency) and apply follow-up improvements:

- Use main's mpdf-psr-http-message-shim-php8-compat.patch (proper PHP 8.5 type
  declarations for Request.php methods)
- Fix TTL=0 handling: non-null TTL <= 0 now stores with 1s expiry (PSR-16)
- Add PSR-16 key validation via validate_key() and validate_iterable()
- Fix PHPStan: toggle_maintenance_mode() return type void

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add docblocks to mock WordPress functions
- Fix Yoda condition violations throughout assert calls
- Suppress emoji output escaping warnings with phpcs:ignore
- Suppress unused \$expiration parameter warning in mock set_site_transient

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 7, 2026

📝 Walkthrough

Walkthrough

The pull request replaces the Symfony Cache dependency with a custom WordPress-based PSR-16 Simple Cache implementation for SSO functionality. Updates include removing the Symfony Cache package, refactoring the SSO cache layer to use the new WordPress_Simple_Cache class, adding type hints for improved code clarity, and introducing comprehensive tests for the new cache implementation.

Changes

Cohort / File(s) Summary
Dependency Removal
composer.json
Removes the symfony/cache ^5.4.29 dependency from the project requirements.
Type Safety Updates
inc/class-maintenance-mode.php
Adds explicit void return type to the toggle_maintenance_mode() method and updates docblock accordingly.
SSO Cache Refactoring
inc/sso/class-sso.php, inc/sso/class-wordpress-simple-cache.php
Replaces Symfony PSR-6/PSR-16 cache stack with custom WordPress-based PSR-16 implementation using site transients and a configurable key prefix for the SSO cache layer.
Cache Implementation Tests
tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php, tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Test.php
Introduces standalone integration test harness and comprehensive PHPUnit test suite verifying PSR-16 compliance, cache operations, TTL handling, data type support, and multi-key operations.

Sequence Diagram(s)

sequenceDiagram
    participant SSO as SSO Class
    participant Cache as WordPress_Simple_Cache
    participant Transient as WordPress Transients API
    
    rect rgba(100, 150, 200, 0.5)
    Note over SSO,Transient: Cache Initialization & Retrieval
    SSO->>Cache: cache() - request cache instance
    Cache->>Cache: lazy initialize with prefix 'wu_sso_'
    end
    
    rect rgba(150, 100, 200, 0.5)
    Note over Cache,Transient: Cache Operations
    Cache->>Transient: get_site_transient(prefixed_key)
    Transient-->>Cache: cached value or default
    Cache-->>SSO: return PSR-16 CacheInterface
    end
    
    rect rgba(200, 100, 150, 0.5)
    Note over Cache,Transient: Store Operation
    SSO->>Cache: set(key, value, ttl)
    Cache->>Cache: validate key & calculate expiration
    Cache->>Transient: set_site_transient(prefixed_key, value, ttl)
    Transient-->>Cache: confirmation
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A cache, once grand with Symfony's might,
Now hops on WordPress transients bright!
Void returns and PSR-16's way,
Dependencies lighten—hip-hop hooray!
🚀 Simpler, faster, WordPress-bound today!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Pr 357' is vague and non-descriptive, using only a branch reference without conveying meaningful information about the changeset. Replace with a descriptive title that summarizes the main changes, such as 'Replace Symfony Cache with WordPress transient-based PSR-16 implementation' or similar.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pr-357

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Mar 7, 2026

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php (1)

103-103: test_ttl_handling() never observes the TTL.

Line 103 discards $expiration, so these assertions only prove that set() returns true. Recording the passed expiration in the mock would let this file catch timeout-calculation bugs instead of masking them.

Also applies to: 329-345

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php` at line 103,
The mock helper set_site_transient currently ignores the $expiration param so
tests like test_ttl_handling() can't verify TTL behavior; modify the mock
implementation (function set_site_transient) to record the passed $expiration
alongside the key and value (e.g., store ['value'=> $value, 'expiration'=>
$expiration] in the same mock storage used by get_site_transient) so assertions
can inspect the recorded expiration; apply the same change to the other mock
implementations referenced around lines 329-345 so all tests can validate
timeout calculations rather than just set() return values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@inc/sso/class-wordpress-simple-cache.php`:
- Around line 99-117: clear() only scans sitemeta and misses transients stored
solely in an external object cache; update the implementation so clearing covers
cache-only keys by using a versioned namespace or an explicit key index: either
(A) implement a namespace/version value (e.g., store "{$this->prefix}_version"
as a site option and prepend it to transient names set via set_site_transient)
and have clear() bump that version to invalidate all cached keys, or (B)
maintain an index (e.g., site option "{$this->prefix}_index") that
set_site_transient records each transient name into via
wp_cache_set/wp_cache_get/wp_cache_delete and
set_site_option/update_site_option, and have clear() iterate that index to call
delete_site_transient and wp_cache_delete for each entry and then clear the
index; locate changes around the clear() method and corresponding set/save code
that calls set_site_transient to ensure both database and object-cache-only
transients are tracked and invalidated.
- Around line 71-80: The set() method currently treats zero/negative TTLs by
forcing a 1-second expiry and convert_ttl_to_seconds() mutates DateTime via
DateTime::add(), collapsing DateInterval TTLs to one second; change
convert_ttl_to_seconds() to avoid mutating $now (use (clone
$now)->add($interval) or DateTimeImmutable->add) so future time is computed
correctly, and update set($key, $value, $ttl = null) to treat null !== $ttl &&
$expiration <= 0 by deleting the key with delete_site_transient($this->prefix .
$key) and returning false (PSR-16 requires deletion of expired items) instead of
forcing a 1-second TTL. Ensure references are to convert_ttl_to_seconds(),
set(), DateInterval, DateTime::add(), and delete_site_transient().

In `@tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php`:
- Around line 77-132: The test runner fails because the plugin file early-exits
when ABSPATH is missing and clear() uses global $wpdb which doesn't exist; fix
by defining a minimal ABSPATH constant in the standalone CLI runner before
requiring inc/sso/class-wordpress-simple-cache.php and/or update the guard in
class-wordpress-simple-cache.php to allow a test mode, and in tests mock a
minimal $wpdb object with an sitemeta property or refactor clear() to use
set_site_transient/delete_site_transient when global $wpdb is not present (refer
to the clear() method and class-wordpress-simple-cache.php). For TTL testing,
update the test mocks for set_site_transient/get_site_transient to record
expiration timestamps (store both value and expiry) and make get_site_transient
return false when expired, then enhance test_ttl_handling() to assert the
expiration behavior (refer to mock_wordpress_functions(), set_site_transient,
get_site_transient, and test_ttl_handling()).

---

Nitpick comments:
In `@tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php`:
- Line 103: The mock helper set_site_transient currently ignores the $expiration
param so tests like test_ttl_handling() can't verify TTL behavior; modify the
mock implementation (function set_site_transient) to record the passed
$expiration alongside the key and value (e.g., store ['value'=> $value,
'expiration'=> $expiration] in the same mock storage used by get_site_transient)
so assertions can inspect the recorded expiration; apply the same change to the
other mock implementations referenced around lines 329-345 so all tests can
validate timeout calculations rather than just set() return values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c596385b-8f96-471a-a450-2774b73d46cf

📥 Commits

Reviewing files that changed from the base of the PR and between 18c9c97 and 8d4c377.

⛔ Files ignored due to path filters (1)
  • composer.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • composer.json
  • inc/class-maintenance-mode.php
  • inc/sso/class-sso.php
  • inc/sso/class-wordpress-simple-cache.php
  • tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php
  • tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Test.php
💤 Files with no reviewable changes (1)
  • composer.json

Comment on lines +71 to +80
public function set($key, $value, $ttl = null) {
$this->validate_key($key);
$expiration = $this->convert_ttl_to_seconds($ttl);

// Non-null TTL <= 0 means item should expire immediately (PSR-16).
if (null !== $ttl && $expiration <= 0) {
$expiration = 1;
}

return set_site_transient($this->prefix . $key, ['v' => $value], $expiration);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In PHP, does DateTime::add() mutate the original object, and what does PSR-16 require a cache implementation to do when set() receives a zero or negative TTL?

💡 Result:

  • PHP DateTime::add(): Yes—it mutates the original DateTime object (it “modifies a DateTime object”) and returns the same (now-modified) object for chaining. If you need non-mutating behavior, use DateTimeImmutable::add(), which returns a new instance. [1]

  • PSR-16 (CacheInterface::set) TTL ≤ 0: If set() receives a zero or negative TTL, the cache implementation MUST delete the item from the cache (if it exists) because it is already expired. [2]

Sources: [1] PHP Manual: DateTime::add(); [2] PHP-FIG PSR-16 specification.


🏁 Script executed:

# Check the set() method at lines 71-80
sed -n '71,80p' inc/sso/class-wordpress-simple-cache.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 432


🏁 Script executed:

# Check the convert_ttl_to_seconds() method at lines 226-238
sed -n '226,238p' inc/sso/class-wordpress-simple-cache.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 376


🏁 Script executed:

# Get context around these lines to verify structure
sed -n '60,85p' inc/sso/class-wordpress-simple-cache.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 913


🏁 Script executed:

# Get context for convert_ttl_to_seconds
sed -n '215,245p' inc/sso/class-wordpress-simple-cache.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 779


DateInterval TTLs collapse to one second due to DateTime::add() mutation; PSR-16 requires deleting expired items, not caching them.

Line 233 mutates $now in place via DateTime::add(), causing $future and $now to reference the same object. Line 234 then computes 0, forcing every DateInterval TTL through the 1-second fallback in Lines 75-78. Additionally, zero or negative TTLs should be deleted per PSR-16, not cached for an extra second.

Proposed fix
 public function set($key, $value, $ttl = null) {
 	$this->validate_key($key);
 	$expiration = $this->convert_ttl_to_seconds($ttl);

-	// Non-null TTL <= 0 means item should expire immediately (PSR-16).
+	// Non-null TTL <= 0 means the item is already expired (PSR-16).
 	if (null !== $ttl && $expiration <= 0) {
-		$expiration = 1;
+		delete_site_transient($this->prefix . $key);
+		return true;
 	}

 	return set_site_transient($this->prefix . $key, ['v' => $value], $expiration);
 }
 protected function convert_ttl_to_seconds($ttl) {
 	if (null === $ttl) {
 		return 0; // No expiration.
 	}

 	if ($ttl instanceof \DateInterval) {
-		$now    = new \DateTime();
+		$now    = new \DateTimeImmutable();
 		$future = $now->add($ttl);
-		return $future->getTimestamp() - $now->getTimestamp();
+		return max(0, $future->getTimestamp() - $now->getTimestamp());
 	}

 	return (int) $ttl;
 }

Also applies to: 226-238

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/sso/class-wordpress-simple-cache.php` around lines 71 - 80, The set()
method currently treats zero/negative TTLs by forcing a 1-second expiry and
convert_ttl_to_seconds() mutates DateTime via DateTime::add(), collapsing
DateInterval TTLs to one second; change convert_ttl_to_seconds() to avoid
mutating $now (use (clone $now)->add($interval) or DateTimeImmutable->add) so
future time is computed correctly, and update set($key, $value, $ttl = null) to
treat null !== $ttl && $expiration <= 0 by deleting the key with
delete_site_transient($this->prefix . $key) and returning false (PSR-16 requires
deletion of expired items) instead of forcing a 1-second TTL. Ensure references
are to convert_ttl_to_seconds(), set(), DateInterval, DateTime::add(), and
delete_site_transient().

Comment on lines +99 to +117
public function clear() {
global $wpdb;

// Get all transient keys with our prefix and delete each via the WordPress API,
// which handles both DB and object cache correctly.
$like_pattern = $wpdb->esc_like('_site_transient_' . $this->prefix) . '%';
$meta_keys = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->prepare(
"SELECT meta_key FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s",
$like_pattern
)
);

foreach ($meta_keys as $meta_key) {
$transient_name = substr($meta_key, strlen('_site_transient_'));
delete_site_transient($transient_name);
}

return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In WordPress core, when wp_using_ext_object_cache() is true, does set_site_transient() write to the sitemeta table or only to the object cache?

💡 Result:

When wp_using_ext_object_cache() is true, set_site_transient() does not write to the database (wp_sitemeta) in WordPress core—it short-circuits to wp_cache_set( $transient, $value, 'site-transient', $expiration ), i.e. object cache only. [1]

It only uses the DB path (via add_site_option() / update_site_option(), which stores network options in wp_sitemeta) when no external object cache is in use. [1], [2]


clear() misses entries stored in the object cache when an external object cache is active.

The implementation discovers keys by scanning $wpdb->sitemeta, but set_site_transient() bypasses the database entirely when an external object cache is active—it writes only to the cache layer. Consequently, clear() returns true without invalidating any transients for this prefix in that configuration. A versioned namespace or explicit key index is necessary to reliably clear all entries.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/sso/class-wordpress-simple-cache.php` around lines 99 - 117, clear() only
scans sitemeta and misses transients stored solely in an external object cache;
update the implementation so clearing covers cache-only keys by using a
versioned namespace or an explicit key index: either (A) implement a
namespace/version value (e.g., store "{$this->prefix}_version" as a site option
and prepend it to transient names set via set_site_transient) and have clear()
bump that version to invalidate all cached keys, or (B) maintain an index (e.g.,
site option "{$this->prefix}_index") that set_site_transient records each
transient name into via wp_cache_set/wp_cache_get/wp_cache_delete and
set_site_option/update_site_option, and have clear() iterate that index to call
delete_site_transient and wp_cache_delete for each entry and then clear the
index; locate changes around the clear() method and corresponding set/save code
that calls set_site_transient to ensure both database and object-cache-only
transients are tracked and invalidated.

Comment on lines +77 to +132
private static function mock_wordpress_functions() {
if (! function_exists('get_site_transient')) {
/**
* Mock get_site_transient for standalone testing.
*
* @param string $key Transient key.
* @return mixed Value or false if not set.
*/
function get_site_transient($key) {
global $_site_transients;
if (! isset($_site_transients)) {
$_site_transients = array();
}
return isset($_site_transients[ $key ]) ? $_site_transients[ $key ] : false;
}
}

if (! function_exists('set_site_transient')) {
/**
* Mock set_site_transient for standalone testing.
*
* @param string $key Transient key.
* @param mixed $value Value to store.
* @param int $expiration Expiration in seconds (unused in mock).
* @return bool Always true.
*/
function set_site_transient($key, $value, $expiration = 0) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
global $_site_transients;
if (! isset($_site_transients)) {
$_site_transients = array();
}
$_site_transients[ $key ] = $value;
return true;
}
}

if (! function_exists('delete_site_transient')) {
/**
* Mock delete_site_transient for standalone testing.
*
* @param string $key Transient key.
* @return bool True if deleted, false if not found.
*/
function delete_site_transient($key) {
global $_site_transients;
if (! isset($_site_transients)) {
$_site_transients = array();
}
if (isset($_site_transients[ $key ])) {
unset($_site_transients[ $key ]);
return true;
}
return false;
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '1,20p' inc/sso/class-wordpress-simple-cache.php
sed -n '74,132p' tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php
sed -n '350,356p' tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 2548


🏁 Script executed:

# Check the clear() method implementation in WordPress_Simple_Cache
sed -n '99,117p' inc/sso/class-wordpress-simple-cache.php

# Find and show the TTL test
rg -n 'test_ttl|test_set_with_expiration' tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php -A 15

# Check if there's any ABSPATH or WordPress bootstrap provided before the require
sed -n '340,360p' tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php

Repository: Ultimate-Multisite/ultimate-multisite

Length of output: 2632


The advertised standalone runner cannot execute as written due to missing WordPress bootstrap.

The main class file (inc/sso/class-wordpress-simple-cache.php) contains a guard that exits when ABSPATH is undefined (line 15). When the CLI runner (lines 350–356) attempts to require this file in standalone mode, the execution stops before any tests run. Additionally, the clear() method (lines 99–117) directly references global $wpdb to query $wpdb->sitemeta, which is unavailable outside a WordPress environment.

The TTL test does not validate expiration handling.

The test_ttl_handling() method (lines 329–345) only asserts that set() returns true. It never verifies that the TTL values are actually stored or respected. The mock set_site_transient() function explicitly ignores the $expiration parameter (marked with a phpcs:ignore comment), so no TTL data is ever captured or tested.

🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 103-103: Avoid unused parameters such as '$expiration'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/WP_Ultimo/SSO/WordPress_Simple_Cache_Integration_Test.php` around lines
77 - 132, The test runner fails because the plugin file early-exits when ABSPATH
is missing and clear() uses global $wpdb which doesn't exist; fix by defining a
minimal ABSPATH constant in the standalone CLI runner before requiring
inc/sso/class-wordpress-simple-cache.php and/or update the guard in
class-wordpress-simple-cache.php to allow a test mode, and in tests mock a
minimal $wpdb object with an sitemeta property or refactor clear() to use
set_site_transient/delete_site_transient when global $wpdb is not present (refer
to the clear() method and class-wordpress-simple-cache.php). For TTL testing,
update the test mocks for set_site_transient/get_site_transient to record
expiration timestamps (store both value and expiry) and make get_site_transient
return false when expired, then enhance test_ttl_handling() to assert the
expiration behavior (refer to mock_wordpress_functions(), set_site_transient,
get_site_transient, and test_ttl_handling()).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant