Skip to content

Commit

Permalink
Add in-database caching for remote assets to reduce live requests
Browse files Browse the repository at this point in the history
  • Loading branch information
zlateska committed Nov 4, 2024
1 parent 6fa5449 commit 9220229
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 65 deletions.
4 changes: 4 additions & 0 deletions includes/Api/Controllers/CacheController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use NewfoldLabs\WP\Module\Patterns\SiteClassification;
use NewfoldLabs\WP\Module\Data\WonderBlocks\Requests\Fetch as WonderBlocksFetchRequest;
use NewfoldLabs\WP\Module\Data\WonderBlocks\WonderBlocks;
use NewfoldLabs\WP\Module\Patterns\CSSUtilities;

/**
* Controller for cache.
Expand Down Expand Up @@ -71,6 +72,9 @@ public static function clear_cache( \WP_REST_Request $request ) {

$response['categories'] = 'Cache cleared';
}

// Refresh the CSS utilities assets.
CSSUtilities::get_instance()->refresh_assets();

return new \WP_REST_Response( $response, 200 );
}
Expand Down
199 changes: 135 additions & 64 deletions includes/CSSUtilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
use NewfoldLabs\WP\Module\Data\WonderBlocks\Requests\Fetch;
class CSSUtilities {

/**
* The single instance of the class.
*
* @var CSSUtilities|null
*/
private static $instance = null;

/**
* The production base URL.
*
Expand All @@ -19,10 +26,22 @@ class CSSUtilities {
*/
protected static $local_base_url = 'http://localhost:8888';

/**
* Get the single instance of the class.
*
* @return CSSUtilities The instance of the class.
*/
public static function get_instance(): CSSUtilities {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}

/**
* Constructor.
*/
public function __construct() {
private function __construct() {
\add_action( 'enqueue_block_assets', array( $this, 'enqueue' ) );
\add_action( 'enqueue_nfd_wonder_blocks_utilities', array( $this, 'enqueue' ) );
}
Expand All @@ -33,46 +52,52 @@ public function __construct() {
* @return void
*/
public function enqueue() {

$base_url = $this->get_base_url();
// Refresh assets if 24 hours have passed since the last refresh.
$this->conditional_refresh_assets();

$remote_css = $base_url . '/assets/css/utilities.css';
$remote_js = $base_url . '/assets/js/utilities.js';

$css_url = $this->is_valid_remote_file( $remote_css )
? $remote_css
: constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.css';
$css_version = $css_url === $remote_css
? strtotime( 'midnight' )
: constant( 'NFD_WONDER_BLOCKS_VERSION' );

$js_url = $this->is_valid_remote_file( $remote_js )
? $remote_js
: constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.js';
$js_version = $js_url === $remote_js
? strtotime( 'midnight' )
: constant( 'NFD_WONDER_BLOCKS_VERSION' );

\wp_register_style(
'nfd-wonder-blocks-utilities',
$css_url,
array(),
$css_version
);

\wp_register_script(
'nfd-wonder-blocks-utilities',
$js_url,
array(),
$js_version
);

\wp_enqueue_style( 'nfd-wonder-blocks-utilities' );
\wp_enqueue_script( 'nfd-wonder-blocks-utilities' );
$css_content = $this->get_asset_content( 'utilities_css' );
$js_content = $this->get_asset_content( 'utilities_js' );

if ( $css_content ) {
\wp_register_style( 'nfd-wonder-blocks-utilities', false );
\wp_enqueue_style( 'nfd-wonder-blocks-utilities');
\wp_add_inline_style( 'nfd-wonder-blocks-utilities', $css_content );
} else {
\wp_enqueue_style(
'nfd-wonder-blocks-utilities',
constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.css',
array(),
constant( 'NFD_WONDER_BLOCKS_VERSION' )
);
}

if ( $js_content ) {
\wp_register_script( 'nfd-wonder-blocks-utilities', false );
\wp_enqueue_script( 'nfd-wonder-blocks-utilities' );
\wp_add_inline_script( 'nfd-wonder-blocks-utilities', $js_content );
} else {
\wp_enqueue_script(
'nfd-wonder-blocks-utilities',
constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.js',
array(),
constant( 'NFD_WONDER_BLOCKS_VERSION' )
);
}

\wp_add_inline_style( 'nfd-wonder-blocks-utilities', $this->get_inline_css() );
}

/**
* Get the content of an asset.
*
* @param string $asset The asset to get the content of.
* @return string The content of the asset.
*/
private function get_asset_content( string $option_key ) {
$sanitized_key = sanitize_key( 'nfd_' . $option_key );
return get_option( $sanitized_key, false );
}

/**
* Generates inline CSS based on the current active theme.
*
Expand All @@ -83,7 +108,6 @@ public function enqueue() {
* @return string The generated CSS.
*/
private function get_inline_css() {

$theme = \wp_get_theme()->get_template();
$css = '';

Expand Down Expand Up @@ -120,7 +144,7 @@ private function get_inline_css() {
--nfd-cp-text-secondary: var(--wp--preset--color--secondary, #000);
}";

$css = "body .is-layout-constrained:has(.wndb-container.is-layout-constrained) > .wndb-container.is-layout-constrained {
$css .= "body .is-layout-constrained:has(.wndb-container.is-layout-constrained) > .wndb-container.is-layout-constrained {
width: 100%;
max-width: unset;
}";
Expand All @@ -141,43 +165,90 @@ private function get_inline_css() {
}

/**
* Check if a remote file is valid.
*
* Stores the resulting HTTP status (or "error") in a transient for 24 hours.
* {@see wp_remote_retrieve_response_code()} returns 200 even for redirects.
*
* @param string $url URL of the remote file.
* Get the base URL
*
* @return string The base URL.
*/
private function is_valid_remote_file( string $url ): bool {
// Reverse the url because transient key length is limited and truncated and the unique part of the URL is its end.
$transient_key = 'nfd_css_utilities_valid_' . strrev($url );
public function get_base_url(): string {
if ( defined( 'NFD_DATA_WB_DEV_MODE' ) && constant( 'NFD_DATA_WB_DEV_MODE' ) ) {
return self::$local_base_url;
}

$status_code = get_transient( $transient_key );
return self::$production_base_url;
}

if( false === $status_code || ! is_numeric( $status_code ) ) {
/**
* Conditionally refresh CSS and JS assets from remote sources if 24 hours have passed.
*
* @return void
*/
public function conditional_refresh_assets() {
$last_refresh = get_option( 'nfd_utilities_last_refresh_time', 0 );
$current_time = time();

if ( ( $current_time - $last_refresh ) > DAY_IN_SECONDS ) {
$this->refresh_assets();
update_option( 'nfd_utilities_last_refresh_time', $current_time );
}
}

$response = \wp_remote_head( $url, array( 'timeout' => 5 ) );
/**
* Refresh CSS and JS assets from remote sources.
* This method can be manually triggered by other actions or hooks as needed.
*
* @return void
*/
public function refresh_assets() {
$this->fetch_and_store_asset( '/assets/css/utilities.css', 'utilities_css' );
$this->fetch_and_store_asset( '/assets/js/utilities.js', 'utilities_js' );
}

$status_code = is_wp_error( $response )
? 'error'
: \wp_remote_retrieve_response_code( $response );
/**
* Fetch and store the asset content in the database with minification.
*
* @param string $path The path of the remote asset.
* @param string $option_key The option key to store the content.
*
* @return void
*/
private function fetch_and_store_asset( string $path, string $option_key ) {
$base_url = $this->get_base_url();
$url = esc_url_raw( $base_url . $path );

set_transient( $transient_key, $status_code, constant( 'DAY_IN_SECONDS' ) );
$response = \wp_remote_get( $url );

if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
$content = wp_remote_retrieve_body( $response );

// Minify the content for storage
$minified_content = $this->minify_content( $content, $path );
$sanitized_key = sanitize_key( 'nfd_' . $option_key );
update_option( $sanitized_key, wp_slash( $minified_content ) );
}

return 200 === intval( $status_code );
}

/**
* Get the base URL
*
* @return string The base URL.
* Minify the CSS or JS content.
*
* @param string $content The content to minify.
* @param string $path The path to determine if it's CSS or JS.
*
* @return string The minified content.
*/
public function get_base_url(): string {
if ( defined( 'NFD_DATA_WB_DEV_MODE' ) && constant( 'NFD_DATA_WB_DEV_MODE' ) ) {
return self::$local_base_url;
private function minify_content( string $content, string $path ): string {
if ( strpos( $path, '.css' ) !== false ) {
// Minify CSS by removing comments, whitespace, etc.
$content = preg_replace( '/\s+/', ' ', $content );
$content = preg_replace( '/\s*([{};:>+~,])\s*/', '$1', $content );
$content = preg_replace( '/;}/', '}', $content );
$content = preg_replace( '/\/\*.*?\*\//', '', $content );
} elseif ( strpos( $path, '.js' ) !== false ) {
// Minify JS by removing comments and whitespace.
$content = preg_replace( '/\/\*.*?\*\//s', '', $content );
$content = preg_replace( '/\s+/', ' ', $content );
$content = preg_replace( '/\s*([{};,:>+\-~])\s*/', '$1', $content );
$content = preg_replace( '/;}/', '}', $content );
}

return self::$production_base_url;
return trim( $content );
}
}
3 changes: 2 additions & 1 deletion includes/Patterns.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public function __construct( Container $container ) {
new CTA();
}

new CSSUtilities();
CSSUtilities::get_instance();

new RestApi();
new BlockStyles();
}
Expand Down

0 comments on commit 9220229

Please sign in to comment.