| 1 |
<?php |
| 2 |
/** |
| 3 |
* Charitable Tools - Email Diagnostics. |
| 4 |
* |
| 5 |
* @package Charitable/Classes/Charitable_Tools_Email_Diagnostics |
| 6 |
* @author David Bisset |
| 7 |
* @copyright Copyright (c) 2023, WP Charitable LLC |
| 8 |
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License |
| 9 |
* @since 1.8.9.2 |
| 10 |
*/ |
| 11 |
|
| 12 |
// Exit if accessed directly. |
| 13 |
if ( ! defined( 'ABSPATH' ) ) { |
| 14 |
exit; |
| 15 |
} |
| 16 |
|
| 17 |
if ( ! class_exists( 'Charitable_Tools_Email_Diagnostics' ) ) : |
| 18 |
|
| 19 |
/** |
| 20 |
* Charitable_Tools_Email_Diagnostics |
| 21 |
* |
| 22 |
* @final |
| 23 |
* @since 1.8.9.2 |
| 24 |
*/ |
| 25 |
class Charitable_Tools_Email_Diagnostics { |
| 26 |
|
| 27 |
/** |
| 28 |
* The single instance of this class. |
| 29 |
* |
| 30 |
* @since 1.8.9.2 |
| 31 |
* |
| 32 |
* @var Charitable_Tools_Email_Diagnostics|null |
| 33 |
*/ |
| 34 |
private static $instance = null; |
| 35 |
|
| 36 |
/** |
| 37 |
* Cache key for diagnostic results. |
| 38 |
* |
| 39 |
* @since 1.8.9.2 |
| 40 |
* @var string |
| 41 |
*/ |
| 42 |
private $cache_key = 'charitable_email_diagnostics_cache'; |
| 43 |
|
| 44 |
/** |
| 45 |
* Cache duration in seconds (5 minutes). |
| 46 |
* |
| 47 |
* @since 1.8.9.2 |
| 48 |
* @var int |
| 49 |
*/ |
| 50 |
private $cache_duration = 300; |
| 51 |
|
| 52 |
/** |
| 53 |
* Priority emails for core functionality testing. |
| 54 |
* |
| 55 |
* @since 1.8.9.2 |
| 56 |
* @var array |
| 57 |
*/ |
| 58 |
private $priority_emails = array( |
| 59 |
'donation_receipt', |
| 60 |
'offline_donation_receipt', |
| 61 |
'new_donation' |
| 62 |
); |
| 63 |
|
| 64 |
/** |
| 65 |
* Set up the class. |
| 66 |
* |
| 67 |
* @since 1.8.9.2 |
| 68 |
*/ |
| 69 |
private function __construct() { |
| 70 |
// Private constructor for singleton |
| 71 |
} |
| 72 |
|
| 73 |
/** |
| 74 |
* Returns and/or create the single instance of this class. |
| 75 |
* |
| 76 |
* @since 1.8.9.2 |
| 77 |
* |
| 78 |
* @return Charitable_Tools_Email_Diagnostics |
| 79 |
*/ |
| 80 |
public static function get_instance() { |
| 81 |
if ( is_null( self::$instance ) ) { |
| 82 |
self::$instance = new self(); |
| 83 |
} |
| 84 |
|
| 85 |
return self::$instance; |
| 86 |
} |
| 87 |
|
| 88 |
/** |
| 89 |
* Get email diagnostics summary for system info display. |
| 90 |
* |
| 91 |
* @since 1.8.9.2 |
| 92 |
* |
| 93 |
* @return string |
| 94 |
*/ |
| 95 |
public function get_email_diagnostics_summary() { |
| 96 |
$diagnostics = $this->get_cached_basic_diagnostics(); |
| 97 |
|
| 98 |
$data = "\n-- Email System Diagnostics\n\n"; |
| 99 |
$data .= sprintf( "Email Health Score: %s (%s)\n", $diagnostics['health_score'], $diagnostics['health_grade'] ); |
| 100 |
$data .= sprintf( "Emails Registered: %d emails\n", $diagnostics['emails_registered_count'] ); |
| 101 |
$data .= sprintf( "Email Access Status: %s\n", $diagnostics['email_access_status'] ); |
| 102 |
$data .= sprintf( "Preview URLs: %s functional\n", $diagnostics['preview_status'] ); |
| 103 |
$data .= sprintf( "Hook Timing: %s\n", $diagnostics['hook_timing'] ); |
| 104 |
$data .= sprintf( "Average Access Time: %s\n", $diagnostics['average_access_time'] ); |
| 105 |
$data .= sprintf( "Caching Detected: %s\n", $diagnostics['caching_detected'] ); |
| 106 |
$data .= sprintf( "Recent Email Errors: %d\n", $diagnostics['recent_errors'] ); |
| 107 |
|
| 108 |
return $data; |
| 109 |
} |
| 110 |
|
| 111 |
/** |
| 112 |
* Get detailed email diagnostics for AJAX response. |
| 113 |
* |
| 114 |
* @since 1.8.9.2 |
| 115 |
* |
| 116 |
* @return array |
| 117 |
*/ |
| 118 |
public function get_detailed_email_diagnostics() { |
| 119 |
// Check for cached results first |
| 120 |
$cached = get_transient( $this->cache_key ); |
| 121 |
if ( false !== $cached ) { |
| 122 |
return $cached; |
| 123 |
} |
| 124 |
|
| 125 |
$diagnostics = array(); |
| 126 |
$start_time = microtime( true ); |
| 127 |
|
| 128 |
try { |
| 129 |
// Run all diagnostic tests |
| 130 |
$diagnostics['email_registration'] = $this->test_email_registration(); |
| 131 |
$diagnostics['email_access'] = $this->test_email_access(); |
| 132 |
$diagnostics['preview_functionality'] = $this->test_preview_functionality(); |
| 133 |
$diagnostics['hook_timing'] = $this->test_hook_timing(); |
| 134 |
$diagnostics['environment_config'] = $this->test_environment_config(); |
| 135 |
$diagnostics['performance'] = $this->test_performance(); |
| 136 |
|
| 137 |
// Calculate overall health score |
| 138 |
$diagnostics['health_score'] = $this->calculate_health_score( $diagnostics ); |
| 139 |
|
| 140 |
// Add timing information |
| 141 |
$diagnostics['execution_time'] = round( ( microtime( true ) - $start_time ) * 1000, 2 ); |
| 142 |
$diagnostics['timestamp'] = current_time( 'Y-m-d H:i:s' ); |
| 143 |
|
| 144 |
// Cache the results |
| 145 |
set_transient( $this->cache_key, $diagnostics, $this->cache_duration ); |
| 146 |
|
| 147 |
} catch ( Exception $e ) { |
| 148 |
$diagnostics['error'] = array( |
| 149 |
'message' => 'Diagnostic test failed: ' . $e->getMessage(), |
| 150 |
'code' => $e->getCode(), |
| 151 |
'file' => $e->getFile(), |
| 152 |
'line' => $e->getLine() |
| 153 |
); |
| 154 |
} |
| 155 |
|
| 156 |
return $diagnostics; |
| 157 |
} |
| 158 |
|
| 159 |
/** |
| 160 |
* Get cached basic diagnostics for system info. |
| 161 |
* |
| 162 |
* @since 1.8.9.2 |
| 163 |
* |
| 164 |
* @return array |
| 165 |
*/ |
| 166 |
private function get_cached_basic_diagnostics() { |
| 167 |
$cached = get_transient( $this->cache_key . '_basic' ); |
| 168 |
if ( false !== $cached ) { |
| 169 |
return $cached; |
| 170 |
} |
| 171 |
|
| 172 |
try { |
| 173 |
$emails_registered = $this->test_email_registration(); |
| 174 |
$email_access = $this->test_email_access(); |
| 175 |
$preview_test = $this->test_preview_functionality(); |
| 176 |
$hook_timing = $this->test_hook_timing(); |
| 177 |
$environment = $this->test_environment_config(); |
| 178 |
|
| 179 |
$basic = array( |
| 180 |
'health_score' => $this->calculate_basic_health_score( $emails_registered, $email_access, $preview_test ), |
| 181 |
'health_grade' => $this->get_health_grade( $this->calculate_basic_health_score( $emails_registered, $email_access, $preview_test ) ), |
| 182 |
'emails_registered_count' => count( $emails_registered['registered_emails'] ?? array() ), |
| 183 |
'email_access_status' => $email_access['status'] ?? 'Unknown', |
| 184 |
'preview_status' => sprintf( '%d/%d', $preview_test['functional_count'] ?? 0, count( $this->priority_emails ) ), |
| 185 |
'hook_timing' => $hook_timing['status'] ?? 'Unknown', |
| 186 |
'average_access_time' => sprintf( '%.1fms', $email_access['average_time'] ?? 0 ), |
| 187 |
'caching_detected' => implode( ', ', $environment['caching_plugins'] ?? array() ) ?: 'None', |
| 188 |
'recent_errors' => $this->count_recent_email_errors() |
| 189 |
); |
| 190 |
|
| 191 |
set_transient( $this->cache_key . '_basic', $basic, $this->cache_duration ); |
| 192 |
return $basic; |
| 193 |
|
| 194 |
} catch ( Exception $e ) { |
| 195 |
return array( |
| 196 |
'health_score' => '0/100', |
| 197 |
'health_grade' => 'Grade: F', |
| 198 |
'emails_registered_count' => 0, |
| 199 |
'email_access_status' => 'Error', |
| 200 |
'preview_status' => '0/' . count( $this->priority_emails ), |
| 201 |
'hook_timing' => 'Error', |
| 202 |
'average_access_time' => '0.0ms', |
| 203 |
'caching_detected' => 'Unknown', |
| 204 |
'recent_errors' => 0 |
| 205 |
); |
| 206 |
} |
| 207 |
} |
| 208 |
|
| 209 |
/** |
| 210 |
* Test email registration functionality. |
| 211 |
* |
| 212 |
* @since 1.8.9.2 |
| 213 |
* |
| 214 |
* @return array |
| 215 |
*/ |
| 216 |
private function test_email_registration() { |
| 217 |
$result = array( |
| 218 |
'test_name' => 'Email Registration', |
| 219 |
'status' => 'fail', |
| 220 |
'score' => 0, |
| 221 |
'max_score' => 20, |
| 222 |
'details' => array(), |
| 223 |
'registered_emails' => array(), |
| 224 |
'timing' => array() |
| 225 |
); |
| 226 |
|
| 227 |
try { |
| 228 |
$start_time = microtime( true ); |
| 229 |
|
| 230 |
// Test helper accessibility |
| 231 |
$emails_helper = null; |
| 232 |
try { |
| 233 |
$emails_helper = charitable_get_helper( 'emails' ); |
| 234 |
$result['details']['helper_accessible'] = true; |
| 235 |
} catch ( Exception $e ) { |
| 236 |
$result['details']['helper_accessible'] = false; |
| 237 |
$result['details']['helper_error'] = $e->getMessage(); |
| 238 |
} |
| 239 |
|
| 240 |
if ( ! $emails_helper ) { |
| 241 |
$result['details']['error'] = 'charitable_get_helper(\'emails\') returned null or false'; |
| 242 |
return $result; |
| 243 |
} |
| 244 |
|
| 245 |
// Test email registration via reflection |
| 246 |
try { |
| 247 |
$reflection = new ReflectionClass( $emails_helper ); |
| 248 |
$method = $reflection->getMethod( 'ensure_emails_registered' ); |
| 249 |
$registration_success = $method->invoke( $emails_helper ); |
| 250 |
$result['details']['registration_method_exists'] = true; |
| 251 |
$result['details']['registration_successful'] = $registration_success; |
| 252 |
} catch ( ReflectionException $e ) { |
| 253 |
$result['details']['registration_method_exists'] = false; |
| 254 |
$result['details']['reflection_error'] = $e->getMessage(); |
| 255 |
} |
| 256 |
|
| 257 |
// Test getting available emails |
| 258 |
$available_emails = $emails_helper->get_available_emails(); |
| 259 |
if ( is_array( $available_emails ) && ! empty( $available_emails ) ) { |
| 260 |
$result['registered_emails'] = $available_emails; |
| 261 |
$result['details']['emails_count'] = count( $available_emails ); |
| 262 |
$result['details']['has_priority_emails'] = $this->check_priority_emails_registered( $available_emails ); |
| 263 |
|
| 264 |
// Check if core emails are present |
| 265 |
$core_emails_present = 0; |
| 266 |
foreach ( $this->priority_emails as $email ) { |
| 267 |
if ( isset( $available_emails[ $email ] ) ) { |
| 268 |
$core_emails_present++; |
| 269 |
} |
| 270 |
} |
| 271 |
$result['details']['core_emails_present'] = $core_emails_present; |
| 272 |
$result['details']['core_emails_total'] = count( $this->priority_emails ); |
| 273 |
|
| 274 |
// Success if we have emails and core ones are present |
| 275 |
if ( $core_emails_present >= 2 ) { |
| 276 |
$result['status'] = 'success'; |
| 277 |
$result['score'] = 20; |
| 278 |
} else { |
| 279 |
$result['status'] = 'partial'; |
| 280 |
$result['score'] = 10; |
| 281 |
} |
| 282 |
} else { |
| 283 |
$result['details']['emails_empty'] = true; |
| 284 |
$result['details']['available_emails_result'] = $available_emails; |
| 285 |
} |
| 286 |
|
| 287 |
$end_time = microtime( true ); |
| 288 |
$result['timing'] = array( |
| 289 |
'duration_ms' => round( ( $end_time - $start_time ) * 1000, 2 ), |
| 290 |
'before_init' => ! did_action( 'init' ), |
| 291 |
'during_init' => doing_action( 'init' ), |
| 292 |
'after_init' => did_action( 'init' ) && ! doing_action( 'init' ) |
| 293 |
); |
| 294 |
|
| 295 |
} catch ( Exception $e ) { |
| 296 |
$result['details']['exception'] = $e->getMessage(); |
| 297 |
$result['details']['exception_trace'] = $e->getTraceAsString(); |
| 298 |
} |
| 299 |
|
| 300 |
return $result; |
| 301 |
} |
| 302 |
|
| 303 |
/** |
| 304 |
* Test email access functionality. |
| 305 |
* |
| 306 |
* @since 1.8.9.2 |
| 307 |
* |
| 308 |
* @return array |
| 309 |
*/ |
| 310 |
private function test_email_access() { |
| 311 |
$result = array( |
| 312 |
'test_name' => 'Email Access', |
| 313 |
'status' => 'fail', |
| 314 |
'score' => 0, |
| 315 |
'max_score' => 20, |
| 316 |
'details' => array(), |
| 317 |
'email_tests' => array(), |
| 318 |
'average_time' => 0 |
| 319 |
); |
| 320 |
|
| 321 |
try { |
| 322 |
$emails_helper = charitable_get_helper( 'emails' ); |
| 323 |
if ( ! $emails_helper ) { |
| 324 |
$result['details']['error'] = 'Email helper not available'; |
| 325 |
return $result; |
| 326 |
} |
| 327 |
|
| 328 |
$total_time = 0; |
| 329 |
$successful_accesses = 0; |
| 330 |
$failed_accesses = 0; |
| 331 |
|
| 332 |
foreach ( $this->priority_emails as $email_id ) { |
| 333 |
$email_test = array( |
| 334 |
'email_id' => $email_id, |
| 335 |
'accessible' => false, |
| 336 |
'class_exists' => false, |
| 337 |
'instantiable' => false, |
| 338 |
'timing_ms' => 0 |
| 339 |
); |
| 340 |
|
| 341 |
$start_time = microtime( true ); |
| 342 |
|
| 343 |
try { |
| 344 |
// Test getting email class |
| 345 |
$email_class = $emails_helper->get_email( $email_id ); |
| 346 |
$email_test['class_name'] = $email_class; |
| 347 |
$email_test['class_retrieved'] = ! empty( $email_class ); |
| 348 |
|
| 349 |
if ( $email_class && class_exists( $email_class ) ) { |
| 350 |
$email_test['class_exists'] = true; |
| 351 |
|
| 352 |
// Test instantiation |
| 353 |
try { |
| 354 |
$email_instance = new $email_class(); |
| 355 |
$email_test['instantiable'] = true; |
| 356 |
$email_test['accessible'] = true; |
| 357 |
|
| 358 |
// Test basic methods |
| 359 |
if ( method_exists( $email_instance, 'get_email_id' ) ) { |
| 360 |
$email_test['get_id_works'] = $email_instance->get_email_id() === $email_id; |
| 361 |
} |
| 362 |
if ( method_exists( $email_instance, 'get_name' ) ) { |
| 363 |
$email_test['has_name'] = ! empty( $email_instance->get_name() ); |
| 364 |
} |
| 365 |
|
| 366 |
// Phase 1 Integration: Test recipient extraction with real donation data |
| 367 |
$email_test['recipient_extraction'] = $this->test_recipient_extraction_for_email( $email_instance, $email_id ); |
| 368 |
|
| 369 |
$successful_accesses++; |
| 370 |
} catch ( Exception $e ) { |
| 371 |
$email_test['instantiation_error'] = $e->getMessage(); |
| 372 |
$failed_accesses++; |
| 373 |
} |
| 374 |
} else { |
| 375 |
$email_test['class_missing'] = true; |
| 376 |
$failed_accesses++; |
| 377 |
} |
| 378 |
|
| 379 |
} catch ( Exception $e ) { |
| 380 |
$email_test['access_error'] = $e->getMessage(); |
| 381 |
$failed_accesses++; |
| 382 |
} |
| 383 |
|
| 384 |
$end_time = microtime( true ); |
| 385 |
$email_test['timing_ms'] = round( ( $end_time - $start_time ) * 1000, 2 ); |
| 386 |
$total_time += $email_test['timing_ms']; |
| 387 |
|
| 388 |
$result['email_tests'][ $email_id ] = $email_test; |
| 389 |
} |
| 390 |
|
| 391 |
// Calculate results |
| 392 |
$result['details']['successful_accesses'] = $successful_accesses; |
| 393 |
$result['details']['failed_accesses'] = $failed_accesses; |
| 394 |
$result['details']['total_emails_tested'] = count( $this->priority_emails ); |
| 395 |
$result['average_time'] = round( $total_time / count( $this->priority_emails ), 1 ); |
| 396 |
|
| 397 |
// Phase 1 Integration: Count recipient extraction failures |
| 398 |
$recipient_failures = 0; |
| 399 |
foreach ( $result['email_tests'] as $email_test ) { |
| 400 |
if ( isset( $email_test['recipient_extraction']['tested'] ) && |
| 401 |
$email_test['recipient_extraction']['tested'] && |
| 402 |
! $email_test['recipient_extraction']['success'] ) { |
| 403 |
$recipient_failures++; |
| 404 |
} |
| 405 |
} |
| 406 |
$result['details']['recipient_extraction_failures'] = $recipient_failures; |
| 407 |
|
| 408 |
// Determine status and score |
| 409 |
if ( $successful_accesses === count( $this->priority_emails ) ) { |
| 410 |
$result['status'] = 'success'; |
| 411 |
$result['score'] = 20; |
| 412 |
|
| 413 |
// Reduce score for recipient extraction failures |
| 414 |
if ( $recipient_failures > 0 ) { |
| 415 |
$result['score'] -= ( $recipient_failures * 3 ); // -3 points per failure |
| 416 |
$result['status'] = 'partial'; |
| 417 |
$result['details']['recipient_warning'] = "Recipient extraction failing for {$recipient_failures} email(s)"; |
| 418 |
} |
| 419 |
} elseif ( $successful_accesses > 0 ) { |
| 420 |
$result['status'] = 'partial'; |
| 421 |
$result['score'] = round( ( $successful_accesses / count( $this->priority_emails ) ) * 20 ); |
| 422 |
|
| 423 |
// Additional penalty for recipient failures |
| 424 |
if ( $recipient_failures > 0 ) { |
| 425 |
$result['score'] -= ( $recipient_failures * 2 ); |
| 426 |
} |
| 427 |
} |
| 428 |
|
| 429 |
// Performance check |
| 430 |
if ( $result['average_time'] > 100 ) { |
| 431 |
$result['details']['performance_warning'] = 'Average access time exceeds 100ms'; |
| 432 |
$result['score'] = max( 0, $result['score'] - 5 ); // Penalty for slow access |
| 433 |
} |
| 434 |
|
| 435 |
} catch ( Exception $e ) { |
| 436 |
$result['details']['exception'] = $e->getMessage(); |
| 437 |
} |
| 438 |
|
| 439 |
return $result; |
| 440 |
} |
| 441 |
|
| 442 |
/** |
| 443 |
* Test email preview functionality. |
| 444 |
* |
| 445 |
* @since 1.8.9.2 |
| 446 |
* |
| 447 |
* @return array |
| 448 |
*/ |
| 449 |
private function test_preview_functionality() { |
| 450 |
$result = array( |
| 451 |
'test_name' => 'Preview Functionality', |
| 452 |
'status' => 'fail', |
| 453 |
'score' => 0, |
| 454 |
'max_score' => 15, |
| 455 |
'details' => array(), |
| 456 |
'preview_tests' => array(), |
| 457 |
'functional_count' => 0 |
| 458 |
); |
| 459 |
|
| 460 |
try { |
| 461 |
$functional_previews = 0; |
| 462 |
|
| 463 |
foreach ( $this->priority_emails as $email_id ) { |
| 464 |
$preview_test = array( |
| 465 |
'email_id' => $email_id, |
| 466 |
'url_generated' => false, |
| 467 |
'endpoint_accessible' => false, |
| 468 |
'preview_works' => false |
| 469 |
); |
| 470 |
|
| 471 |
try { |
| 472 |
// Generate preview URL |
| 473 |
$preview_url = add_query_arg( |
| 474 |
array( |
| 475 |
'charitable_action' => 'preview_email', |
| 476 |
'email_id' => $email_id, |
| 477 |
'_nonce' => wp_create_nonce( 'email_preview' ) |
| 478 |
), |
| 479 |
site_url() |
| 480 |
); |
| 481 |
|
| 482 |
$preview_test['url_generated'] = true; |
| 483 |
$preview_test['preview_url'] = $preview_url; |
| 484 |
|
| 485 |
// Test endpoint accessibility (HEAD request only - no actual email sending) |
| 486 |
$response = wp_remote_head( $preview_url, array( |
| 487 |
'timeout' => 10, |
| 488 |
'user-agent' => 'Charitable Email Diagnostics' |
| 489 |
) ); |
| 490 |
|
| 491 |
if ( ! is_wp_error( $response ) ) { |
| 492 |
$status_code = wp_remote_retrieve_response_code( $response ); |
| 493 |
$preview_test['status_code'] = $status_code; |
| 494 |
$preview_test['endpoint_accessible'] = true; |
| 495 |
|
| 496 |
// Check for successful response or redirect (both are acceptable for previews) |
| 497 |
if ( in_array( $status_code, array( 200, 301, 302 ) ) ) { |
| 498 |
$preview_test['preview_works'] = true; |
| 499 |
$functional_previews++; |
| 500 |
} |
| 501 |
} else { |
| 502 |
$preview_test['endpoint_error'] = $response->get_error_message(); |
| 503 |
} |
| 504 |
|
| 505 |
} catch ( Exception $e ) { |
| 506 |
$preview_test['exception'] = $e->getMessage(); |
| 507 |
} |
| 508 |
|
| 509 |
$result['preview_tests'][ $email_id ] = $preview_test; |
| 510 |
} |
| 511 |
|
| 512 |
$result['functional_count'] = $functional_previews; |
| 513 |
$result['details']['total_tested'] = count( $this->priority_emails ); |
| 514 |
|
| 515 |
// Determine status and score |
| 516 |
if ( $functional_previews === count( $this->priority_emails ) ) { |
| 517 |
$result['status'] = 'success'; |
| 518 |
$result['score'] = 15; |
| 519 |
} elseif ( $functional_previews > 0 ) { |
| 520 |
$result['status'] = 'partial'; |
| 521 |
$result['score'] = round( ( $functional_previews / count( $this->priority_emails ) ) * 15 ); |
| 522 |
} |
| 523 |
|
| 524 |
} catch ( Exception $e ) { |
| 525 |
$result['details']['exception'] = $e->getMessage(); |
| 526 |
} |
| 527 |
|
| 528 |
return $result; |
| 529 |
} |
| 530 |
|
| 531 |
/** |
| 532 |
* Test hook timing and initialization order. |
| 533 |
* |
| 534 |
* @since 1.8.9.2 |
| 535 |
* |
| 536 |
* @return array |
| 537 |
*/ |
| 538 |
private function test_hook_timing() { |
| 539 |
$result = array( |
| 540 |
'test_name' => 'Hook Timing', |
| 541 |
'status' => 'success', |
| 542 |
'score' => 15, |
| 543 |
'max_score' => 15, |
| 544 |
'details' => array() |
| 545 |
); |
| 546 |
|
| 547 |
try { |
| 548 |
// Check WordPress hook status |
| 549 |
$result['details']['init_completed'] = did_action( 'init' ); |
| 550 |
$result['details']['admin_init_completed'] = did_action( 'admin_init' ); |
| 551 |
$result['details']['currently_doing_init'] = doing_action( 'init' ); |
| 552 |
$result['details']['currently_doing_admin_init'] = doing_action( 'admin_init' ); |
| 553 |
|
| 554 |
// Check current action context |
| 555 |
$current_action = current_action(); |
| 556 |
$result['details']['current_action'] = $current_action ?: 'none'; |
| 557 |
|
| 558 |
// Check plugin load order |
| 559 |
$active_plugins = get_option( 'active_plugins', array() ); |
| 560 |
$charitable_position = false; |
| 561 |
foreach ( $active_plugins as $index => $plugin ) { |
| 562 |
if ( strpos( $plugin, 'charitable' ) !== false ) { |
| 563 |
$charitable_position = $index; |
| 564 |
break; |
| 565 |
} |
| 566 |
} |
| 567 |
$result['details']['charitable_plugin_position'] = $charitable_position; |
| 568 |
$result['details']['total_active_plugins'] = count( $active_plugins ); |
| 569 |
|
| 570 |
// Check for timing conflicts |
| 571 |
$timing_issues = array(); |
| 572 |
|
| 573 |
if ( ! did_action( 'init' ) && ! doing_action( 'init' ) ) { |
| 574 |
$timing_issues[] = 'Emails accessed before init hook'; |
| 575 |
$result['score'] -= 5; |
| 576 |
} |
| 577 |
|
| 578 |
if ( doing_action( 'plugins_loaded' ) ) { |
| 579 |
$timing_issues[] = 'Accessing during plugins_loaded (may cause timing issues)'; |
| 580 |
$result['score'] -= 3; |
| 581 |
} |
| 582 |
|
| 583 |
// Check for AJAX context |
| 584 |
if ( wp_doing_ajax() ) { |
| 585 |
$result['details']['ajax_context'] = true; |
| 586 |
// AJAX is actually fine for email diagnostics |
| 587 |
} |
| 588 |
|
| 589 |
// Check for cron context |
| 590 |
if ( wp_doing_cron() ) { |
| 591 |
$result['details']['cron_context'] = true; |
| 592 |
$timing_issues[] = 'Running in cron context (may have limited functionality)'; |
| 593 |
$result['score'] -= 2; |
| 594 |
} |
| 595 |
|
| 596 |
$result['details']['timing_issues'] = $timing_issues; |
| 597 |
|
| 598 |
// Overall status |
| 599 |
if ( empty( $timing_issues ) ) { |
| 600 |
$result['status'] = 'success'; |
| 601 |
} elseif ( $result['score'] > 10 ) { |
| 602 |
$result['status'] = 'warning'; |
| 603 |
} else { |
| 604 |
$result['status'] = 'fail'; |
| 605 |
} |
| 606 |
|
| 607 |
} catch ( Exception $e ) { |
| 608 |
$result['details']['exception'] = $e->getMessage(); |
| 609 |
$result['status'] = 'fail'; |
| 610 |
$result['score'] = 0; |
| 611 |
} |
| 612 |
|
| 613 |
return $result; |
| 614 |
} |
| 615 |
|
| 616 |
/** |
| 617 |
* Test environment configuration. |
| 618 |
* |
| 619 |
* @since 1.8.9.2 |
| 620 |
* |
| 621 |
* @return array |
| 622 |
*/ |
| 623 |
private function test_environment_config() { |
| 624 |
$result = array( |
| 625 |
'test_name' => 'Environment Configuration', |
| 626 |
'status' => 'success', |
| 627 |
'score' => 15, |
| 628 |
'max_score' => 15, |
| 629 |
'details' => array(), |
| 630 |
'caching_plugins' => array(), |
| 631 |
'environment_info' => array() |
| 632 |
); |
| 633 |
|
| 634 |
try { |
| 635 |
// Detect caching plugins |
| 636 |
$known_caching_plugins = array( |
| 637 |
'wp-rocket/wp-rocket.php' => 'WP Rocket', |
| 638 |
'w3-total-cache/w3-total-cache.php' => 'W3 Total Cache', |
| 639 |
'wp-super-cache/wp-cache.php' => 'WP Super Cache', |
| 640 |
'litespeed-cache/litespeed-cache.php' => 'LiteSpeed Cache', |
| 641 |
'wp-fastest-cache/wpFastestCache.php' => 'WP Fastest Cache', |
| 642 |
'hummingbird-performance/wp-hummingbird.php' => 'Hummingbird', |
| 643 |
'autoptimize/autoptimize.php' => 'Autoptimize' |
| 644 |
); |
| 645 |
|
| 646 |
$active_plugins = get_option( 'active_plugins', array() ); |
| 647 |
foreach ( $known_caching_plugins as $plugin_file => $plugin_name ) { |
| 648 |
if ( in_array( $plugin_file, $active_plugins ) ) { |
| 649 |
$result['caching_plugins'][] = $plugin_name; |
| 650 |
} |
| 651 |
} |
| 652 |
|
| 653 |
// Check object cache |
| 654 |
$result['details']['object_cache_enabled'] = wp_using_ext_object_cache(); |
| 655 |
|
| 656 |
// Check OPcache |
| 657 |
$result['details']['opcache_enabled'] = function_exists( 'opcache_get_status' ) && opcache_get_status(); |
| 658 |
|
| 659 |
// Environment information |
| 660 |
$result['environment_info'] = array( |
| 661 |
'php_version' => PHP_VERSION, |
| 662 |
'wordpress_version' => get_bloginfo( 'version' ), |
| 663 |
'charitable_version' => charitable()->get_version(), |
| 664 |
'memory_limit' => ini_get( 'memory_limit' ), |
| 665 |
'max_execution_time' => ini_get( 'max_execution_time' ), |
| 666 |
'is_multisite' => is_multisite(), |
| 667 |
'debug_enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG, |
| 668 |
'charitable_debug' => defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG |
| 669 |
); |
| 670 |
|
| 671 |
// Check email environment |
| 672 |
$result['details']['smtp_configured'] = $this->is_smtp_configured(); |
| 673 |
$result['details']['mail_function_available'] = function_exists( 'mail' ); |
| 674 |
$result['details']['wp_mail_available'] = function_exists( 'wp_mail' ); |
| 675 |
|
| 676 |
// Score adjustments |
| 677 |
if ( ! empty( $result['caching_plugins'] ) ) { |
| 678 |
$result['details']['caching_warning'] = 'Caching plugins detected - may affect email timing'; |
| 679 |
$result['score'] -= 2; |
| 680 |
} |
| 681 |
|
| 682 |
if ( ! $result['details']['wp_mail_available'] ) { |
| 683 |
$result['details']['mail_error'] = 'wp_mail function not available'; |
| 684 |
$result['score'] -= 5; |
| 685 |
$result['status'] = 'warning'; |
| 686 |
} |
| 687 |
|
| 688 |
} catch ( Exception $e ) { |
| 689 |
$result['details']['exception'] = $e->getMessage(); |
| 690 |
$result['status'] = 'fail'; |
| 691 |
$result['score'] = 0; |
| 692 |
} |
| 693 |
|
| 694 |
return $result; |
| 695 |
} |
| 696 |
|
| 697 |
/** |
| 698 |
* Test performance metrics. |
| 699 |
* |
| 700 |
* @since 1.8.9.2 |
| 701 |
* |
| 702 |
* @return array |
| 703 |
*/ |
| 704 |
private function test_performance() { |
| 705 |
$result = array( |
| 706 |
'test_name' => 'Performance', |
| 707 |
'status' => 'success', |
| 708 |
'score' => 15, |
| 709 |
'max_score' => 15, |
| 710 |
'details' => array(), |
| 711 |
'metrics' => array() |
| 712 |
); |
| 713 |
|
| 714 |
try { |
| 715 |
$start_time = microtime( true ); |
| 716 |
$start_memory = memory_get_usage( true ); |
| 717 |
|
| 718 |
// Test email helper performance |
| 719 |
$helper_start = microtime( true ); |
| 720 |
$emails_helper = charitable_get_helper( 'emails' ); |
| 721 |
$helper_time = ( microtime( true ) - $helper_start ) * 1000; |
| 722 |
|
| 723 |
// Test email registration performance |
| 724 |
$reg_start = microtime( true ); |
| 725 |
if ( $emails_helper ) { |
| 726 |
$available_emails = $emails_helper->get_available_emails(); |
| 727 |
$reg_time = ( microtime( true ) - $reg_start ) * 1000; |
| 728 |
} else { |
| 729 |
$reg_time = 0; |
| 730 |
$result['details']['helper_unavailable'] = true; |
| 731 |
} |
| 732 |
|
| 733 |
// Calculate metrics |
| 734 |
$total_time = ( microtime( true ) - $start_time ) * 1000; |
| 735 |
$memory_used = memory_get_usage( true ) - $start_memory; |
| 736 |
|
| 737 |
$result['metrics'] = array( |
| 738 |
'helper_access_time_ms' => round( $helper_time, 2 ), |
| 739 |
'registration_time_ms' => round( $reg_time, 2 ), |
| 740 |
'total_time_ms' => round( $total_time, 2 ), |
| 741 |
'memory_used_kb' => round( $memory_used / 1024, 2 ), |
| 742 |
'peak_memory_mb' => round( memory_get_peak_usage( true ) / 1024 / 1024, 2 ) |
| 743 |
); |
| 744 |
|
| 745 |
// Performance scoring |
| 746 |
if ( $helper_time > 50 ) { |
| 747 |
$result['details']['slow_helper'] = 'Email helper access > 50ms'; |
| 748 |
$result['score'] -= 3; |
| 749 |
} |
| 750 |
|
| 751 |
if ( $reg_time > 100 ) { |
| 752 |
$result['details']['slow_registration'] = 'Email registration > 100ms'; |
| 753 |
$result['score'] -= 5; |
| 754 |
} |
| 755 |
|
| 756 |
if ( $memory_used > 1024 * 1024 ) { // 1MB |
| 757 |
$result['details']['high_memory'] = 'High memory usage during email operations'; |
| 758 |
$result['score'] -= 2; |
| 759 |
} |
| 760 |
|
| 761 |
// Overall status |
| 762 |
if ( $result['score'] >= 13 ) { |
| 763 |
$result['status'] = 'excellent'; |
| 764 |
} elseif ( $result['score'] >= 10 ) { |
| 765 |
$result['status'] = 'good'; |
| 766 |
} elseif ( $result['score'] >= 7 ) { |
| 767 |
$result['status'] = 'fair'; |
| 768 |
} else { |
| 769 |
$result['status'] = 'poor'; |
| 770 |
} |
| 771 |
|
| 772 |
} catch ( Exception $e ) { |
| 773 |
$result['details']['exception'] = $e->getMessage(); |
| 774 |
$result['status'] = 'fail'; |
| 775 |
$result['score'] = 0; |
| 776 |
} |
| 777 |
|
| 778 |
return $result; |
| 779 |
} |
| 780 |
|
| 781 |
/** |
| 782 |
* Calculate overall health score from diagnostic results. |
| 783 |
* |
| 784 |
* @since 1.8.9.2 |
| 785 |
* |
| 786 |
* @param array $diagnostics Full diagnostic results. |
| 787 |
* @return array Health score details. |
| 788 |
*/ |
| 789 |
private function calculate_health_score( $diagnostics ) { |
| 790 |
$total_score = 0; |
| 791 |
$max_score = 100; |
| 792 |
$category_scores = array(); |
| 793 |
|
| 794 |
// Extract scores from each category |
| 795 |
$categories = array( |
| 796 |
'email_registration', |
| 797 |
'email_access', |
| 798 |
'preview_functionality', |
| 799 |
'hook_timing', |
| 800 |
'environment_config', |
| 801 |
'performance' |
| 802 |
); |
| 803 |
|
| 804 |
foreach ( $categories as $category ) { |
| 805 |
if ( isset( $diagnostics[ $category ]['score'] ) ) { |
| 806 |
$score = (int) $diagnostics[ $category ]['score']; |
| 807 |
$max = (int) $diagnostics[ $category ]['max_score']; |
| 808 |
$total_score += $score; |
| 809 |
$category_scores[ $category ] = array( |
| 810 |
'score' => $score, |
| 811 |
'max_score' => $max, |
| 812 |
'percentage' => $max > 0 ? round( ( $score / $max ) * 100 ) : 0 |
| 813 |
); |
| 814 |
} |
| 815 |
} |
| 816 |
|
| 817 |
$percentage = round( ( $total_score / $max_score ) * 100 ); |
| 818 |
$grade = $this->get_health_grade( $percentage ); |
| 819 |
|
| 820 |
return array( |
| 821 |
'total_score' => $total_score, |
| 822 |
'max_score' => $max_score, |
| 823 |
'percentage' => $percentage, |
| 824 |
'grade' => $grade, |
| 825 |
'category_scores' => $category_scores, |
| 826 |
'interpretation' => $this->get_score_interpretation( $percentage ) |
| 827 |
); |
| 828 |
} |
| 829 |
|
| 830 |
/** |
| 831 |
* Calculate basic health score for system info display. |
| 832 |
* |
| 833 |
* @since 1.8.9.2 |
| 834 |
* |
| 835 |
* @param array $email_registration Email registration test results. |
| 836 |
* @param array $email_access Email access test results. |
| 837 |
* @param array $preview_test Preview functionality test results. |
| 838 |
* @return int Health score percentage. |
| 839 |
*/ |
| 840 |
private function calculate_basic_health_score( $email_registration, $email_access, $preview_test ) { |
| 841 |
$total_score = 0; |
| 842 |
$max_score = 55; // Registration (20) + Access (20) + Preview (15) |
| 843 |
|
| 844 |
$total_score += $email_registration['score'] ?? 0; |
| 845 |
$total_score += $email_access['score'] ?? 0; |
| 846 |
$total_score += $preview_test['score'] ?? 0; |
| 847 |
|
| 848 |
return round( ( $total_score / $max_score ) * 100 ); |
| 849 |
} |
| 850 |
|
| 851 |
/** |
| 852 |
* Get health grade based on percentage. |
| 853 |
* |
| 854 |
* @since 1.8.9.2 |
| 855 |
* |
| 856 |
* @param int $percentage Health score percentage. |
| 857 |
* @return string Grade letter with descriptive text. |
| 858 |
*/ |
| 859 |
private function get_health_grade( $percentage ) { |
| 860 |
if ( $percentage >= 90 ) { |
| 861 |
return 'Grade: A'; |
| 862 |
} elseif ( $percentage >= 80 ) { |
| 863 |
return 'Grade: B'; |
| 864 |
} elseif ( $percentage >= 70 ) { |
| 865 |
return 'Grade: C'; |
| 866 |
} elseif ( $percentage >= 60 ) { |
| 867 |
return 'Grade: D'; |
| 868 |
} else { |
| 869 |
return 'Grade: F'; |
| 870 |
} |
| 871 |
} |
| 872 |
|
| 873 |
/** |
| 874 |
* Get score interpretation and recommendations. |
| 875 |
* |
| 876 |
* @since 1.8.9.2 |
| 877 |
* |
| 878 |
* @param int $percentage Health score percentage. |
| 879 |
* @return string Interpretation text. |
| 880 |
*/ |
| 881 |
private function get_score_interpretation( $percentage ) { |
| 882 |
if ( $percentage >= 90 ) { |
| 883 |
return 'Excellent: Email system is functioning optimally with no issues detected.'; |
| 884 |
} elseif ( $percentage >= 80 ) { |
| 885 |
return 'Good: Email system is working well with minor issues that do not affect core functionality.'; |
| 886 |
} elseif ( $percentage >= 70 ) { |
| 887 |
return 'Fair: Email system has some issues that may affect performance or reliability.'; |
| 888 |
} elseif ( $percentage >= 60 ) { |
| 889 |
return 'Poor: Email system has significant issues that need attention.'; |
| 890 |
} else { |
| 891 |
return 'Critical: Email system has major problems that require immediate investigation.'; |
| 892 |
} |
| 893 |
} |
| 894 |
|
| 895 |
/** |
| 896 |
* Check if priority emails are registered. |
| 897 |
* |
| 898 |
* @since 1.8.9.2 |
| 899 |
* |
| 900 |
* @param array $available_emails Available emails array. |
| 901 |
* @return bool True if priority emails are registered. |
| 902 |
*/ |
| 903 |
private function check_priority_emails_registered( $available_emails ) { |
| 904 |
foreach ( $this->priority_emails as $email ) { |
| 905 |
if ( ! isset( $available_emails[ $email ] ) ) { |
| 906 |
return false; |
| 907 |
} |
| 908 |
} |
| 909 |
return true; |
| 910 |
} |
| 911 |
|
| 912 |
/** |
| 913 |
* Check if SMTP is configured. |
| 914 |
* |
| 915 |
* @since 1.8.9.2 |
| 916 |
* |
| 917 |
* @return bool True if SMTP appears to be configured. |
| 918 |
*/ |
| 919 |
private function is_smtp_configured() { |
| 920 |
// Check for common SMTP plugins |
| 921 |
$smtp_plugins = array( |
| 922 |
'wp-mail-smtp/wp_mail_smtp.php', |
| 923 |
'easy-wp-smtp/easy-wp-smtp.php', |
| 924 |
'post-smtp/postman-smtp.php', |
| 925 |
'wp-smtp/wp-smtp.php' |
| 926 |
); |
| 927 |
|
| 928 |
$active_plugins = get_option( 'active_plugins', array() ); |
| 929 |
foreach ( $smtp_plugins as $plugin ) { |
| 930 |
if ( in_array( $plugin, $active_plugins ) ) { |
| 931 |
return true; |
| 932 |
} |
| 933 |
} |
| 934 |
|
| 935 |
// Check for manual SMTP configuration |
| 936 |
if ( defined( 'WPMS_ON' ) && WPMS_ON ) { |
| 937 |
return true; |
| 938 |
} |
| 939 |
|
| 940 |
return false; |
| 941 |
} |
| 942 |
|
| 943 |
/** |
| 944 |
* Count recent email errors from logs. |
| 945 |
* |
| 946 |
* @since 1.8.9.2 |
| 947 |
* @since 1.8.9.5 Enhanced to connect with Phase 1 error logging improvements. |
| 948 |
* |
| 949 |
* @return int Number of recent email errors. |
| 950 |
*/ |
| 951 |
private function count_recent_email_errors() { |
| 952 |
$error_count = 0; |
| 953 |
|
| 954 |
try { |
| 955 |
// Connect to Phase 1 enhanced error logging via activities table (Pro only) |
| 956 |
$registered_tables = (array) apply_filters( 'charitable_db_tables', array() ); |
| 957 |
if ( function_exists( 'charitable_get_table' ) && array_key_exists( 'charitable_activities', $registered_tables ) ) { |
| 958 |
$activities_table = charitable_get_table( 'charitable_activities' ); |
| 959 |
if ( $activities_table ) { |
| 960 |
global $wpdb; |
| 961 |
$table_name = $activities_table->get_table_name(); |
| 962 |
$seven_days_ago = date( 'Y-m-d H:i:s', strtotime( '-7 days' ) ); |
| 963 |
|
| 964 |
// Count email failures from the last 7 days |
| 965 |
$error_count = (int) $wpdb->get_var( $wpdb->prepare( |
| 966 |
"SELECT COUNT(*) FROM {$table_name} |
| 967 |
WHERE type = 'form_error' |
| 968 |
AND error_type = 'email_failure' |
| 969 |
AND timestamp >= %s", |
| 970 |
$seven_days_ago |
| 971 |
) ); |
| 972 |
} |
| 973 |
} |
| 974 |
} catch ( Exception $e ) { |
| 975 |
// Fail silently for diagnostics - don't break the diagnostic system |
| 976 |
if ( charitable_is_debug() ) { |
| 977 |
error_log( 'Charitable Email Diagnostics: Error counting recent email errors - ' . $e->getMessage() ); |
| 978 |
} |
| 979 |
} |
| 980 |
|
| 981 |
return $error_count; |
| 982 |
} |
| 983 |
|
| 984 |
/** |
| 985 |
* Test recipient extraction for a specific email with real donation data. |
| 986 |
* |
| 987 |
* @since 1.8.9.5 Phase 1 Integration |
| 988 |
* @since 1.8.10 Handle array recipients to prevent fatal TypeError in is_email(). |
| 989 |
* |
| 990 |
* @param object $email_instance Email instance to test. |
| 991 |
* @param string $email_id Email ID being tested. |
| 992 |
* @return array Test results. |
| 993 |
*/ |
| 994 |
private function test_recipient_extraction_for_email( $email_instance, $email_id ) { |
| 995 |
$extraction_test = array( |
| 996 |
'tested' => false, |
| 997 |
'success' => false, |
| 998 |
'recipient_valid' => false, |
| 999 |
'recipient_value' => '', |
| 1000 |
'donation_context' => 'none', |
| 1001 |
'error' => null |
| 1002 |
); |
| 1003 |
|
| 1004 |
try { |
| 1005 |
// Skip recipient extraction test for emails that don't need donations |
| 1006 |
$non_donation_emails = array( 'password_reset', 'email_verification' ); |
| 1007 |
if ( in_array( $email_id, $non_donation_emails ) ) { |
| 1008 |
$extraction_test['tested'] = true; |
| 1009 |
$extraction_test['success'] = true; |
| 1010 |
$extraction_test['recipient_value'] = 'N/A - No donation required'; |
| 1011 |
return $extraction_test; |
| 1012 |
} |
| 1013 |
|
| 1014 |
// Find a recent completed donation for testing |
| 1015 |
$recent_donations = get_posts( array( |
| 1016 |
'post_type' => 'donation', |
| 1017 |
'post_status' => 'charitable-completed', |
| 1018 |
'posts_per_page' => 1, |
| 1019 |
'orderby' => 'date', |
| 1020 |
'order' => 'DESC' |
| 1021 |
) ); |
| 1022 |
|
| 1023 |
if ( empty( $recent_donations ) ) { |
| 1024 |
$extraction_test['donation_context'] = 'no_donations'; |
| 1025 |
$extraction_test['error'] = 'No completed donations available for testing'; |
| 1026 |
return $extraction_test; |
| 1027 |
} |
| 1028 |
|
| 1029 |
$donation = charitable_get_donation( $recent_donations[0]->ID ); |
| 1030 |
if ( ! $donation ) { |
| 1031 |
$extraction_test['donation_context'] = 'invalid_donation'; |
| 1032 |
$extraction_test['error'] = 'Could not load donation object'; |
| 1033 |
return $extraction_test; |
| 1034 |
} |
| 1035 |
|
| 1036 |
$extraction_test['donation_context'] = 'donation_' . $donation->get_donation_id(); |
| 1037 |
$extraction_test['tested'] = true; |
| 1038 |
|
| 1039 |
// Create new email instance with donation context |
| 1040 |
$email_class = get_class( $email_instance ); |
| 1041 |
$test_email = new $email_class( array( 'donation' => $donation ) ); |
| 1042 |
|
| 1043 |
// Test recipient extraction |
| 1044 |
if ( method_exists( $test_email, 'get_recipient' ) ) { |
| 1045 |
$recipient = $test_email->get_recipient(); |
| 1046 |
$extraction_test['recipient_value'] = $recipient; |
| 1047 |
if ( is_array( $recipient ) ) { |
| 1048 |
$extraction_test['recipient_valid'] = ! empty( $recipient ) && ( array_filter( $recipient, 'is_email' ) === $recipient ); |
| 1049 |
$extraction_test['success'] = ! empty( $recipient ); |
| 1050 |
} else { |
| 1051 |
$extraction_test['recipient_valid'] = is_email( $recipient ); |
| 1052 |
$extraction_test['success'] = ! empty( $recipient ) && is_email( $recipient ); |
| 1053 |
} |
| 1054 |
} else { |
| 1055 |
$extraction_test['error'] = 'get_recipient method not available'; |
| 1056 |
} |
| 1057 |
|
| 1058 |
} catch ( Exception $e ) { |
| 1059 |
$extraction_test['error'] = $e->getMessage(); |
| 1060 |
$extraction_test['exception_file'] = basename( $e->getFile() ); |
| 1061 |
$extraction_test['exception_line'] = $e->getLine(); |
| 1062 |
} |
| 1063 |
|
| 1064 |
return $extraction_test; |
| 1065 |
} |
| 1066 |
|
| 1067 |
/** |
| 1068 |
* Clear diagnostic cache. |
| 1069 |
* |
| 1070 |
* @since 1.8.9.2 |
| 1071 |
* |
| 1072 |
* @return bool True if cache was cleared. |
| 1073 |
*/ |
| 1074 |
public function clear_cache() { |
| 1075 |
$result1 = delete_transient( $this->cache_key ); |
| 1076 |
$result2 = delete_transient( $this->cache_key . '_basic' ); |
| 1077 |
return $result1 || $result2; |
| 1078 |
} |
| 1079 |
} |
| 1080 |
|
| 1081 |
endif; |