| @@ -112,8 +112,13 @@ | ||
| 112 | 112 | 'options' => array( 'litespeed.conf.cache' ), |
| 113 | 113 | 'paths' => array( 'litespeed', 'cache/litespeed' ), |
| 114 | 114 | 'dropin_tokens' => array( 'LiteSpeed_Cache', 'LSCWP' ), |
| 115 | 115 | ), |
| 116 | + // It caches at server level and writes no drop-in, so its | |
| 117 | + // own switch is the only proof of whether it serves pages. | |
| 118 | + // GridPane keeps it installed on OpenLiteSpeed and turns | |
| 119 | + // the page cache on or off there. (#653) | |
| 120 | + 'page_cache_state' => array( self::class, 'litespeed_page_cache_state' ), | |
| 116 | 121 | ), |
| 117 | 122 | 'w3-total-cache/w3-total-cache.php' => array( |
| 118 | 123 | 'label' => 'W3 Total Cache', |
| 119 | 124 | 'capabilities' => array( self::CAP_PAGE_CACHE, self::CAP_OBJECT_CACHE, self::CAP_MINIFY, self::CAP_PRELOAD, self::CAP_CDN ), |
| @@ -462,8 +467,11 @@ | ||
| 462 | 467 | 'family' => (string) ( $entry['family'] ?? $entry['label'] ?? $file ), |
| 463 | 468 | 'capabilities' => array_values( (array) ( $entry['capabilities'] ?? array() ) ), |
| 464 | 469 | 'strategy' => (array) ( $entry['strategy'] ?? array() ), |
| 465 | 470 | 'signals' => (array) ( $entry['signals'] ?? array() ), |
| 471 | + // Reads the plugin's own page-cache setting: true on, false | |
| 472 | + // off, null when it cannot be read. See page_cache_state(). | |
| 473 | + 'page_cache_state' => is_callable( $entry['page_cache_state'] ?? null ) ? $entry['page_cache_state'] : null, | |
| 466 | 474 | ); |
| 467 | 475 | } |
| 468 | 476 | |
| 469 | 477 | self::$cache = $catalog; |
| @@ -499,8 +507,93 @@ | ||
| 499 | 507 | */ |
| 500 | 508 | public static function is_page_cache( string $plugin_file ): bool { |
| 501 | 509 | $entry = self::get( $plugin_file ); |
| 502 | 510 | return null !== $entry && in_array( self::CAP_PAGE_CACHE, $entry['capabilities'], true ); |
| 511 | + } | |
| 512 | + | |
| 513 | + /** | |
| 514 | + * Is this plugin's own page cache switched on? | |
| 515 | + * | |
| 516 | + * True when its settings say on, false when they say off, null when we | |
| 517 | + * cannot tell (no reader for this plugin, or the setting is not stored | |
| 518 | + * where we look). "Active" and "caching pages" are different facts: a | |
| 519 | + * plugin can stay active for its other features with its page cache off, | |
| 520 | + * and only false lets a caller treat it as not caching. Null keeps the | |
| 521 | + * old "it is active, so it may be caching" answer. | |
| 522 | + * | |
| 523 | + * Readers only read options. They never load the plugin's code. | |
| 524 | + */ | |
| 525 | + public static function page_cache_state( string $plugin_file ): ?bool { | |
| 526 | + $entry = self::get( $plugin_file ); | |
| 527 | + if ( null === $entry || ! is_callable( $entry['page_cache_state'] ) ) { | |
| 528 | + return null; | |
| 529 | + } | |
| 530 | + $state = call_user_func( $entry['page_cache_state'] ); | |
| 531 | + return is_bool( $state ) ? $state : null; | |
| 532 | + } | |
| 533 | + | |
| 534 | + /** | |
| 535 | + * LiteSpeed Cache's page-cache switch, read the way its own | |
| 536 | + * Conf::define_cache() decides it (checked against 7.9): | |
| 537 | + * | |
| 538 | + * - `cache` is 1 (on), 0 (off), or on multisite 2, "use the network | |
| 539 | + * setting", which lives in the network's own `litespeed.conf.cache`; | |
| 540 | + * - QUIC.cloud CDN (`cdn-quic`) turns the page cache on by itself; | |
| 541 | + * - Toolbox > "Disable All Features" (`debug-disable_all`) turns | |
| 542 | + * everything off, whatever `cache` says. | |
| 543 | + * | |
| 544 | + * Without a LiteSpeed web server or QUIC.cloud its page cache has | |
| 545 | + * nothing to run on, so "on" proves nothing there and the answer is | |
| 546 | + * null. "Off" is off on every server. | |
| 547 | + */ | |
| 548 | + public static function litespeed_page_cache_state(): ?bool { | |
| 549 | + if ( ! function_exists( 'get_option' ) ) { | |
| 550 | + return null; | |
| 551 | + } | |
| 552 | + | |
| 553 | + if ( self::option_is_on( get_option( 'litespeed.conf.debug-disable_all', null ) ) ) { | |
| 554 | + return false; | |
| 555 | + } | |
| 556 | + // "Disable All Features for 24 hours" stores when the pause ends, and | |
| 557 | + // LiteSpeed Cache stands down until then (its Debug2::is_tmp_disable()). | |
| 558 | + $paused_until = get_option( 'litespeed.conf.debug-disable_tmp', 0 ); | |
| 559 | + if ( is_numeric( $paused_until ) && time() < (int) $paused_until ) { | |
| 560 | + return false; | |
| 561 | + } | |
| 562 | + | |
| 563 | + $cache = get_option( 'litespeed.conf.cache', null ); | |
| 564 | + if ( null === $cache || false === $cache || ! is_scalar( $cache ) ) { | |
| 565 | + // Not stored per setting: LiteSpeed Cache 3.x or older, or not | |
| 566 | + // set up yet. Unknown, not off. | |
| 567 | + return null; | |
| 568 | + } | |
| 569 | + | |
| 570 | + $on = 1 === (int) $cache; | |
| 571 | + if ( 2 === (int) $cache ) { | |
| 572 | + if ( ! function_exists( 'is_multisite' ) || ! is_multisite() || ! function_exists( 'get_site_option' ) ) { | |
| 573 | + return null; | |
| 574 | + } | |
| 575 | + $network = get_site_option( 'litespeed.conf.cache', null ); | |
| 576 | + if ( null === $network || ! is_scalar( $network ) ) { | |
| 577 | + return null; | |
| 578 | + } | |
| 579 | + $on = self::option_is_on( $network ); | |
| 580 | + } | |
| 581 | + | |
| 582 | + $quic = self::option_is_on( get_option( 'litespeed.conf.cdn-quic', null ) ); | |
| 583 | + if ( $quic ) { | |
| 584 | + return true; | |
| 585 | + } | |
| 586 | + if ( ! $on ) { | |
| 587 | + return false; | |
| 588 | + } | |
| 589 | + | |
| 590 | + return Server::LITESPEED === Server::type() ? true : null; | |
| 591 | + } | |
| 592 | + | |
| 593 | + /** A LiteSpeed Cache switch value as stored: '1', 1, true are on. */ | |
| 594 | + private static function option_is_on( $value ): bool { | |
| 595 | + return is_scalar( $value ) && 1 === (int) $value; | |
| 503 | 596 | } |
| 504 | 597 | |
| 505 | 598 | /** |
| 506 | 599 | * Match an advanced-cache.php body against the catalog's drop-in tokens. |