| 1 |
<?php |
| 2 |
/** |
| 3 |
* Templately transient scan/delete support helpers. |
| 4 |
* |
| 5 |
* Moved VERBATIM from modules/developer-tools/Developer.php (the |
| 6 |
* `get_templately_transients*` / `delete_templately_transients` / `get_last_transient_cleanup` |
| 7 |
* / `get_transient_management_info` static methods) so the behaviour — the `_transient__templately_` |
| 8 |
* prefix scan, the `_transient_timeout_%` exclusion, the per-transient delete loop, the |
| 9 |
* `templately_last_transient_cleanup` option write, and the returned array shapes — stays |
| 10 |
* byte-identical. Only the namespace and the `self::debug_log()` → {@see Helper::log()} |
| 11 |
* call sites changed (the old `Developer::debug_log()` was itself a thin delegate to Kernel). |
| 12 |
* |
| 13 |
* Option key is unchanged: `templately_last_transient_cleanup`. |
| 14 |
* |
| 15 |
* @package Templately |
| 16 |
*/ |
| 17 |
|
| 18 |
namespace Templately\Modules\Utilities\Cleanup\Tasks\Support; |
| 19 |
|
| 20 |
use Templately\Utils\Helper; |
| 21 |
|
| 22 |
class Transients { |
| 23 |
|
| 24 |
/** |
| 25 |
* Derive a transient key from its stored option name. |
| 26 |
* |
| 27 |
* The one pure fragment of {@see delete_templately_transients()} — extracted so it can be |
| 28 |
* unit-tested without a DB. Behaviour-neutral: it is the exact |
| 29 |
* `str_replace( '_transient_', '', … )` the delete loop always used (strips the WordPress |
| 30 |
* `_transient_` option prefix so the remainder can be passed to `delete_transient()`). |
| 31 |
* |
| 32 |
* @param string $option_name The `wp_options` option_name (e.g. `_transient__templately_foo`). |
| 33 |
* @return string The transient key (e.g. `_templately_foo`). |
| 34 |
*/ |
| 35 |
public static function option_name_to_transient_key( $option_name ) { |
| 36 |
return str_replace( '_transient_', '', $option_name ); |
| 37 |
} |
| 38 |
|
| 39 |
/** |
| 40 |
* Get all Templately transients from the database |
| 41 |
* |
| 42 |
* @since 3.4.0 |
| 43 |
* @return array Array of transient objects with option_name |
| 44 |
*/ |
| 45 |
public static function get_templately_transients() { |
| 46 |
global $wpdb; |
| 47 |
|
| 48 |
// Get all transients that start with '_templately_' prefix |
| 49 |
// Exclude timeout entries as they are automatically handled by WordPress |
| 50 |
// Only select option_name to avoid exposing cached data values |
| 51 |
$transients = $wpdb->get_results( |
| 52 |
$wpdb->prepare( |
| 53 |
"SELECT option_name FROM {$wpdb->options} |
| 54 |
WHERE option_name LIKE %s |
| 55 |
AND option_name NOT LIKE %s |
| 56 |
ORDER BY option_name", |
| 57 |
'_transient__templately_%', |
| 58 |
'_transient_timeout_%' |
| 59 |
) |
| 60 |
); |
| 61 |
|
| 62 |
Helper::log( sprintf( 'Found %d Templately transients', count( $transients ) ), 'transient_management' ); |
| 63 |
|
| 64 |
return $transients ?: []; |
| 65 |
} |
| 66 |
|
| 67 |
/** |
| 68 |
* Get count of Templately transients |
| 69 |
* |
| 70 |
* @since 3.4.0 |
| 71 |
* @return int Number of Templately transients |
| 72 |
*/ |
| 73 |
public static function get_templately_transients_count() { |
| 74 |
global $wpdb; |
| 75 |
|
| 76 |
$count = $wpdb->get_var( |
| 77 |
$wpdb->prepare( |
| 78 |
"SELECT COUNT(*) FROM {$wpdb->options} |
| 79 |
WHERE option_name LIKE %s |
| 80 |
AND option_name NOT LIKE %s", |
| 81 |
'_transient__templately_%', |
| 82 |
'_transient_timeout_%' |
| 83 |
) |
| 84 |
); |
| 85 |
|
| 86 |
return intval( $count ); |
| 87 |
} |
| 88 |
|
| 89 |
/** |
| 90 |
* Delete all Templately transients |
| 91 |
* |
| 92 |
* @since 3.4.0 |
| 93 |
* @return array Result array with success status, deleted count, and message |
| 94 |
*/ |
| 95 |
public static function delete_templately_transients() { |
| 96 |
Helper::log( 'Starting Templately transients deletion', 'transient_management' ); |
| 97 |
|
| 98 |
// Get all Templately transients before deletion for logging |
| 99 |
$transients = self::get_templately_transients(); |
| 100 |
$total_found = count( $transients ); |
| 101 |
|
| 102 |
if ( $total_found === 0 ) { |
| 103 |
Helper::log( 'No Templately transients found to delete', 'transient_management' ); |
| 104 |
return [ |
| 105 |
'success' => true, |
| 106 |
'deleted_count' => 0, |
| 107 |
'total_found' => 0, |
| 108 |
'message' => __( 'No Templately transients found to delete.', 'templately' ), |
| 109 |
]; |
| 110 |
} |
| 111 |
|
| 112 |
$deleted_count = 0; |
| 113 |
$failed_deletions = []; |
| 114 |
|
| 115 |
// Delete each transient using WordPress delete_transient function |
| 116 |
foreach ( $transients as $transient ) { |
| 117 |
// Extract the key by removing the '_transient_' prefix |
| 118 |
$key = self::option_name_to_transient_key( $transient->option_name ); |
| 119 |
|
| 120 |
if ( delete_transient( $key ) ) { |
| 121 |
$deleted_count++; |
| 122 |
Helper::log( "Successfully deleted transient: {$key}", 'transient_management' ); |
| 123 |
} else { |
| 124 |
$failed_deletions[] = $key; |
| 125 |
Helper::log( "Failed to delete transient: {$key}", 'transient_management' ); |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 129 |
// Store deletion timestamp and statistics |
| 130 |
$deletion_info = [ |
| 131 |
'timestamp' => current_time( 'mysql' ), |
| 132 |
'deleted_count' => $deleted_count, |
| 133 |
'total_found' => $total_found, |
| 134 |
'failed_count' => count( $failed_deletions ), |
| 135 |
]; |
| 136 |
|
| 137 |
update_option( 'templately_last_transient_cleanup', $deletion_info ); |
| 138 |
|
| 139 |
// Log summary |
| 140 |
Helper::log( |
| 141 |
sprintf( |
| 142 |
'Transient deletion completed: %d/%d deleted successfully', |
| 143 |
$deleted_count, |
| 144 |
$total_found |
| 145 |
), |
| 146 |
'transient_management' |
| 147 |
); |
| 148 |
|
| 149 |
if ( ! empty( $failed_deletions ) ) { |
| 150 |
Helper::log( |
| 151 |
sprintf( 'Failed to delete %d transients: %s', count( $failed_deletions ), implode( ', ', $failed_deletions ) ), |
| 152 |
'transient_management' |
| 153 |
); |
| 154 |
} |
| 155 |
|
| 156 |
$success = $deleted_count > 0; |
| 157 |
$message = $success |
| 158 |
? sprintf( |
| 159 |
/* translators: %1$d: number of deleted transients, %2$d: total found transients */ |
| 160 |
__( 'Successfully deleted %1$d of %2$d Templately transients.', 'templately' ), |
| 161 |
$deleted_count, |
| 162 |
$total_found |
| 163 |
) |
| 164 |
: __( 'Failed to delete any transients.', 'templately' ); |
| 165 |
|
| 166 |
return [ |
| 167 |
'success' => $success, |
| 168 |
'deleted_count' => $deleted_count, |
| 169 |
'total_found' => $total_found, |
| 170 |
'failed_count' => count( $failed_deletions ), |
| 171 |
'failed_keys' => $failed_deletions, |
| 172 |
'message' => $message, |
| 173 |
]; |
| 174 |
} |
| 175 |
|
| 176 |
/** |
| 177 |
* Get last transient cleanup information |
| 178 |
* |
| 179 |
* @since 3.4.0 |
| 180 |
* @return array|false Cleanup information or false if never run |
| 181 |
*/ |
| 182 |
public static function get_last_transient_cleanup() { |
| 183 |
return get_option( 'templately_last_transient_cleanup', false ); |
| 184 |
} |
| 185 |
|
| 186 |
/** |
| 187 |
* Get transient management information for API responses |
| 188 |
* |
| 189 |
* @since 3.4.0 |
| 190 |
* @return array Transient management data |
| 191 |
*/ |
| 192 |
public static function get_transient_management_info() { |
| 193 |
$count = self::get_templately_transients_count(); |
| 194 |
$last_cleanup = self::get_last_transient_cleanup(); |
| 195 |
|
| 196 |
return [ |
| 197 |
'transient_count' => $count, |
| 198 |
'last_cleanup' => $last_cleanup, |
| 199 |
'has_transients' => $count > 0, |
| 200 |
]; |
| 201 |
} |
| 202 |
} |
| 203 |
|