diff --git a/components/cacheExclusion/index.js b/components/cacheExclusion/index.js
index 74697b0..b031e2e 100644
--- a/components/cacheExclusion/index.js
+++ b/components/cacheExclusion/index.js
@@ -2,41 +2,56 @@ import {
Button,
Container,
TextareaField,
+ Checkbox,
} from '@newfold/ui-component-library';
const CacheExclusion = ( { methods, constants } ) => {
const [ isEdited, setIsEdited ] = methods.useState( false );
const [ isError, setIsError ] = methods.useState( false );
const [ isSaved, setIsSaved ] = methods.useState( false );
- const [ currentValue, setCurrentValue ] = methods.useState(
- methods.NewfoldRuntime.sdk.cacheExclusion
+
+ // Separate states for excluded URLs and error page exclusion
+ const [ excludedUrls, setExcludedUrls ] = methods.useState(
+ methods.NewfoldRuntime.sdk.performance.excludedUrls || ''
);
- const [ cacheExclusion, setCacheExclusion ] = methods.useState(
- methods.NewfoldRuntime.sdk.cacheExclusion
+ const [ doNotCacheErrorPages, setDoNotCacheErrorPages ] = methods.useState(
+ methods.NewfoldRuntime.sdk.performance.doNotCacheErrorPages || false
);
+
const apiUrl = methods.NewfoldRuntime.createApiUrl(
'/newfold-performance/v1/cache-exclusion/update'
);
- const handleCacheExclusionChange = ( e ) => {
- if ( e.target.value !== currentValue ) {
+ // Handle changes to excluded URLs
+ const handleExcludedUrlsChange = ( e ) => {
+ if ( e.target.value !== excludedUrls ) {
setIsEdited( true );
} else {
setIsEdited( false );
}
- setCurrentValue( e.target.value );
+ setExcludedUrls( e.target.value );
+ };
+
+ // Handle checkbox toggle for error page exclusion
+ const handleDoNotCacheErrorPagesChange = () => {
+ const newValue = ! doNotCacheErrorPages;
+ setDoNotCacheErrorPages( newValue );
+ setIsEdited( true );
};
- const handlingSaveButton = () => {
+ // Save settings to the API
+ const handleSaveButton = () => {
methods
.apiFetch( {
url: apiUrl,
method: 'POST',
- data: { cacheExclusion: currentValue },
+ data: {
+ excludedUrls,
+ doNotCacheErrorPages,
+ },
} )
.then( () => {
setIsSaved( true );
- setCacheExclusion( currentValue );
setIsEdited( false );
} )
.catch( ( error ) => {
@@ -44,14 +59,18 @@ const CacheExclusion = ( { methods, constants } ) => {
} );
};
+ // Update notices and store on save/error
methods.useUpdateEffect( () => {
methods.setStore( {
...constants.store,
- CacheExclusion: cacheExclusion,
+ performance: {
+ excludedUrls,
+ doNotCacheErrorPages,
+ },
} );
methods.makeNotice(
- 'cache-exlusion-notice',
+ 'cache-exclusion-notice',
constants.text.cacheExclusionTitle,
! isError ? constants.text.cacheExclusionSaved : isError,
! isError ? 'success' : 'error',
@@ -65,19 +84,29 @@ const CacheExclusion = ( { methods, constants } ) => {
description={ constants.text.cacheExclusionDescription }
>
+
+
{ isEdited && (
diff --git a/components/performance/defaultText.js b/components/performance/defaultText.js
index bba4251..5287888 100644
--- a/components/performance/defaultText.js
+++ b/components/performance/defaultText.js
@@ -73,14 +73,18 @@ const defaultText = {
),
cacheExclusionSaved: __( 'Cache Exclusion saved', 'wp-module-performance' ),
cacheExclusionSaveButton: __( 'Save', 'wp-module-performance' ),
- // Skip 404
+ doNotCacheErrorPagesLabel: __(
+ 'Exclude Error Pages from Cache',
+ 'wp-module-performance'
+ ),
+ // Skip 404
skip404Title: __( 'Skip 404', 'wp-module-performance' ),
skip404Description: __(
'When enabled, static resources like images and fonts will use a default server 404 page and not WordPress 404 pages. Pages and posts will continue using WordPress for 404 pages. This can considerably speed up your website if a static resource like an image or font is missing.',
'wp-module-performance'
),
skip404NoticeTitle: __( 'Skip 404 saved', 'wp-module-performance' ),
- skip404Notice: __( 'Skip 404 saved', 'wp-module-performance' ),
+ skip404Notice: __( 'Skip 404 saved', 'wp-module-performance' ),
// Image Optimization
imageOptimizationSettingsTitle: __(
'Image Optimization',
diff --git a/includes/CacheExclusion.php b/includes/CacheExclusion.php
index 39d8977..8249b86 100644
--- a/includes/CacheExclusion.php
+++ b/includes/CacheExclusion.php
@@ -17,7 +17,7 @@ class CacheExclusion {
protected $container;
/**
- * Option used to store all pages should be excluded from cache.
+ * Option used to store cache exclusion settings.
*
* @var string
*/
@@ -33,6 +33,7 @@ public function __construct( Container $container ) {
add_filter( 'newfold-runtime', array( $this, 'add_to_runtime' ) );
}
+
/**
* Add values to the runtime object.
*
@@ -41,6 +42,20 @@ public function __construct( Container $container ) {
* @return array
*/
public function add_to_runtime( $sdk ) {
- return array_merge( $sdk, array( 'cacheExclusion' => get_option( self::OPTION_CACHE_EXCLUSION, get_default_cache_exclusions() ) ) );
+ $cache_exclusion = get_option( self::OPTION_CACHE_EXCLUSION, $this->get_default_cache_exclusion() );
+
+ return array_merge( $sdk, $cache_exclusion );
+ }
+
+ /**
+ * Get default cache exclusion settings.
+ *
+ * @return array
+ */
+ private function get_default_cache_exclusion() {
+ return array(
+ 'excludedUrls' => get_default_cache_exclusions(),
+ 'doNotCacheErrorPages' => false,
+ );
}
}
diff --git a/includes/CacheTypes/Browser.php b/includes/CacheTypes/Browser.php
index c90899a..8874024 100644
--- a/includes/CacheTypes/Browser.php
+++ b/includes/CacheTypes/Browser.php
@@ -37,9 +37,7 @@ public static function shouldEnable( Container $container ) {
* Constructor.
*/
public function __construct() {
-
new OptionListener( Performance::OPTION_CACHE_LEVEL, array( __CLASS__, 'maybeAddRules' ) );
-
new OptionListener( CacheExclusion::OPTION_CACHE_EXCLUSION, array( __CLASS__, 'exclusionChange' ) );
add_filter( 'newfold_update_htaccess', array( $this, 'onRewrite' ) );
@@ -53,7 +51,7 @@ public function onRewrite() {
}
/**
- * Manage on exlcusion option change.
+ * Manage on exclusion option change.
*/
public static function exclusionChange() {
self::maybeAddRules( getCacheLevel() );
@@ -83,7 +81,6 @@ public static function removeRules() {
* @return bool
*/
public static function addRules( $cacheLevel ) {
-
$fileTypeExpirations = self::getFileTypeExpirations( $cacheLevel );
$tab = "\t";
@@ -100,22 +97,45 @@ public static function addRules( $cacheLevel ) {
}
$rules[] = '';
- $cache_exclusion = get_option( CacheExclusion::OPTION_CACHE_EXCLUSION, '' );
- if ( is_string( $cache_exclusion ) && '' !== $cache_exclusion ) {
- $cache_exclusion_parameters = array_map( 'trim', explode( ',', sanitize_text_field( get_option( CacheExclusion::OPTION_CACHE_EXCLUSION, '' ) ) ) );
+ $cache_exclusion = get_option(
+ CacheExclusion::OPTION_CACHE_EXCLUSION,
+ array(
+ 'excludedUrls' => '',
+ 'doNotCacheErrorPages' => false,
+ )
+ );
+
+ if ( ! empty( $cache_exclusion['excludedUrls'] ) ) {
+ $cache_exclusion_parameters = array_map( 'trim', explode( ',', sanitize_text_field( $cache_exclusion['excludedUrls'] ) ) );
$cache_exclusion_parameters = implode( '|', $cache_exclusion_parameters );
// Add the cache exclusion rules.
$rules[] = '';
- $rules[] = 'RewriteEngine On';
- $rules[] = "RewriteCond %{REQUEST_URI} ^/({$cache_exclusion_parameters}) [NC]";
- $rules[] = '';
- $rules[] = 'Header set Cache-Control "no-cache, no-store, must-revalidate"';
- $rules[] = 'Header set Pragma "no-cache"';
- $rules[] = 'Header set Expires 0';
+ $rules[] = "{$tab}RewriteEngine On";
+ $rules[] = "{$tab}RewriteCond %{REQUEST_URI} ^/({$cache_exclusion_parameters}) [NC]";
+ $rules[] = "{$tab}";
+ $rules[] = "{$tab}{$tab}Header set Cache-Control \"no-cache, no-store, must-revalidate\"";
+ $rules[] = "{$tab}{$tab}Header set Pragma \"no-cache\"";
+ $rules[] = "{$tab}{$tab}Header set Expires 0";
+ $rules[] = "{$tab}";
$rules[] = '';
- $rules[] = '';
- // Add the end of the rules about cache exclusion.
+
+ }
+
+ // Handle "Do Not Cache Error Pages"
+ if ( ! empty( $cache_exclusion['doNotCacheErrorPages'] ) ) {
+ $expr_condition = '"expr=%{REQUEST_STATUS} >= 400 && %{REQUEST_STATUS} < 600"';
+ $rules = array_merge(
+ $rules,
+ array(
+ "{$tab}# Set Cache-Control headers for 400 and 500 status codes",
+ '',
+ "{$tab}Header always set Cache-Control \"no-store, no-cache, must-revalidate\" {$expr_condition}",
+ "{$tab}Header always set Pragma \"no-cache\" {$expr_condition}",
+ "{$tab}Header always set Expires 0 {$expr_condition}",
+ '',
+ )
+ );
}
$htaccess = new htaccess( self::MARKER );
diff --git a/includes/RestApi/CacheExclusionController.php b/includes/RestApi/CacheExclusionController.php
index ce056f4..8ec8d92 100644
--- a/includes/RestApi/CacheExclusionController.php
+++ b/includes/RestApi/CacheExclusionController.php
@@ -42,6 +42,7 @@ public function register_routes() {
),
)
);
+
\register_rest_route(
$this->namespace,
$this->rest_base . '/update',
@@ -50,6 +51,32 @@ public function register_routes() {
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'update_settings' ),
'permission_callback' => array( Permissions::class, 'rest_is_authorized_admin' ),
+ 'args' => array(
+ 'excludedUrls' => array(
+ 'type' => 'string',
+ 'description' => 'Comma-separated string of URLs to exclude from caching.',
+ 'required' => true, // Now marked as required
+ 'sanitize_callback' => function ( $value ) {
+ // Sanitize each URL in the comma-separated string
+ return implode(
+ ',',
+ array_map( 'sanitize_text_field', explode( ',', $value ) )
+ );
+ },
+ ),
+
+ 'doNotCacheErrorPages' => array(
+ 'type' => 'boolean',
+ 'description' => 'Whether to prevent caching of error pages (400 and 500).',
+ 'required' => true,
+ 'sanitize_callback' => 'rest_sanitize_boolean',
+ 'validate_callback' => function ( $param ) {
+ // Ensure the value is a valid boolean or equivalent
+ return is_bool( $param ) || in_array( $param, array( 'true', 'false', true, false ), true );
+ },
+ ),
+
+ ),
),
)
);
@@ -61,14 +88,23 @@ public function register_routes() {
* @return \WP_REST_Response
*/
public function get_settings() {
+ // Retrieve the cache exclusion option once
+ $cache_exclusion = get_option( CacheExclusion::OPTION_CACHE_EXCLUSION, get_default_cache_exclusions() );
+
+ // Extract the specific keys
+ $excluded_urls = $cache_exclusion['excludedUrls'] ?? '';
+ $do_not_cache_error_pages = $cache_exclusion['doNotCacheErrorPages'] ?? false;
+
return new \WP_REST_Response(
array(
- 'cacheExclusion' => get_option( CacheExclusion::OPTION_CACHE_EXCLUSION, get_default_cache_exclusions() ),
+ 'excludedUrls' => $excluded_urls,
+ 'doNotCacheErrorPages' => $do_not_cache_error_pages,
),
200
);
}
+
/**
* Update the settings
*
@@ -76,8 +112,24 @@ public function get_settings() {
* @return \WP_REST_Response
*/
public function update_settings( \WP_REST_Request $request ) {
- $cache_exclusion = $request->get_param( 'cacheExclusion' );
- if ( update_option( CacheExclusion::OPTION_CACHE_EXCLUSION, $cache_exclusion ) ) {
+
+ // Retrieve current settings and merge with defaults
+ $current_cache_exclusion = get_option( CacheExclusion::OPTION_CACHE_EXCLUSION, array() );
+
+ // Extract and sanitize the new values from the request
+ $excluded_urls = $request->get_param( 'excludedUrls' );
+ $do_not_cache_error_pages = $request->get_param( 'doNotCacheErrorPages' );
+
+ // Merge the updated values into the current settings
+ $updated_cache_exclusion = array_merge(
+ $current_cache_exclusion,
+ array(
+ 'excludedUrls' => $excluded_urls,
+ 'doNotCacheErrorPages' => $do_not_cache_error_pages,
+ )
+ );
+
+ if ( update_option( CacheExclusion::OPTION_CACHE_EXCLUSION, $updated_cache_exclusion ) ) {
return new \WP_REST_Response(
array(
'result' => true,
diff --git a/styles/styles.css b/styles/styles.css
index 50b61cb..5ac0ba0 100644
--- a/styles/styles.css
+++ b/styles/styles.css
@@ -1,22 +1,23 @@
.nfd-container__block.newfold-link-prefetch .nfd-toggle-field.nfd-mb-6 {
display: flex;
flex-direction: row;
- }
-.nfd-performance-jetpack-boost-upsell{
+}
+
+.nfd-performance-jetpack-boost-upsell {
position: relative;
}
-.nfd-performance-jetpack-boost-upsell:before {
- content: '';
+.nfd-performance-jetpack-boost-upsell::before {
+ content: "";
display: block;
width: 100%;
height: 100%;
- background-color: rgba(255,255,0,0.1);
+ background-color: rgba(255, 255, 0, 0.1);
position: absolute;
}
-.nfd-performance-jetpack-boost-container-install-activate-button{
+.nfd-performance-jetpack-boost-container-install-activate-button {
position: absolute;
width: 300px;
left: calc(50% - 150px);
@@ -24,12 +25,12 @@
z-index: 10;
}
-.nfd-performance-jetpack-boost-container-install-activate-button svg{
+.nfd-performance-jetpack-boost-container-install-activate-button svg {
display: inline-block;
margin-right: 10px;
}
-.nfd-performance-jetpack-boost-container-install-activate-button button{
+.nfd-performance-jetpack-boost-container-install-activate-button button {
padding: 10px;
border-radius: 6px;
width: 100%;
@@ -39,16 +40,16 @@
justify-content: left;
}
-.nfd-performance-jetpack-boost-single-option .child-field .wrap-button button{
+.nfd-performance-jetpack-boost-single-option .child-field .wrap-button button {
text-decoration: underline;
- margin: 10px 0 0 0;
+ margin: 10px 0 0 0;
}
-.nfd-performance-jetpack-boost-single-option-container{
- margin-bottom: 20px;
+.nfd-performance-jetpack-boost-single-option-container {
+ margin-bottom: 20px;
}
-.margin20{
+.margin20 {
margin: 20px 0;
}
@@ -59,3 +60,12 @@
.newfold-image-optimization a {
color: #05c !important;
}
+
+.nfd-performance-cache-exclusion-checkbox {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.nfd-performance-save-cache-exclusion-button {
+ margin-top: 10px !important;
+}