Files
care-book-block-ultimate/BACKUP-ESSENTIALS/PRODUCTION-READY/care-booking-block-ultimate/includes/class-asset-optimizer.php
Emanuel Almeida 38bb926742 chore: add spec-kit and standardize signatures
- Added GitHub spec-kit for development workflow
- Standardized file signatures to Descomplicar® format
- Updated development configuration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-12 01:27:34 +01:00

510 lines
16 KiB
PHP

/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php
/**
* Asset Optimizer for Care Booking Block plugin
* Provides enterprise-grade asset minification and optimization
*
* @package CareBookingBlock
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Asset Optimizer class for maximum performance
*/
class Care_Booking_Asset_Optimizer
{
/**
* Cache key for asset versions
*/
const ASSET_VERSION_KEY = 'care_booking_asset_versions';
/**
* Cache duration for assets (24 hours)
*/
const ASSET_CACHE_DURATION = DAY_IN_SECONDS;
/**
* Initialize asset optimization
*/
public static function init()
{
// Enqueue optimized assets
add_action('wp_enqueue_scripts', [__CLASS__, 'enqueue_optimized_frontend_assets'], 5);
add_action('admin_enqueue_scripts', [__CLASS__, 'enqueue_optimized_admin_assets'], 5);
// Asset optimization hooks
add_filter('script_loader_src', [__CLASS__, 'optimize_script_src'], 10, 2);
add_filter('style_loader_src', [__CLASS__, 'optimize_style_src'], 10, 2);
// Preload critical assets
add_action('wp_head', [__CLASS__, 'preload_critical_assets'], 1);
// Asset combination and minification
add_action('wp_footer', [__CLASS__, 'output_combined_assets'], 25);
}
/**
* Enqueue optimized frontend assets
*/
public static function enqueue_optimized_frontend_assets()
{
if (is_admin() || !self::should_load_frontend_assets()) {
return;
}
$version = self::get_asset_version();
$min_suffix = self::get_min_suffix();
// Optimized CSS with intelligent loading
wp_enqueue_style(
'care-booking-frontend',
CARE_BOOKING_BLOCK_PLUGIN_URL . "public/css/frontend{$min_suffix}.css",
[],
$version,
'all'
);
// Optimized JavaScript with async loading for non-critical
wp_enqueue_script(
'care-booking-frontend',
CARE_BOOKING_BLOCK_PLUGIN_URL . "public/js/frontend{$min_suffix}.js",
['jquery'],
$version,
true // Load in footer
);
// Add async/defer attributes for better performance
add_filter('script_loader_tag', [__CLASS__, 'add_script_attributes'], 10, 3);
}
/**
* Enqueue optimized admin assets
*/
public static function enqueue_optimized_admin_assets($hook)
{
// Only load on Care Booking admin pages
if (!self::is_care_booking_admin_page($hook)) {
return;
}
$version = self::get_asset_version();
$min_suffix = self::get_min_suffix();
// Combined and minified admin CSS
wp_enqueue_style(
'care-booking-admin',
CARE_BOOKING_BLOCK_PLUGIN_URL . "admin/css/admin-style{$min_suffix}.css",
[],
$version,
'all'
);
// Combined and minified admin JavaScript
wp_enqueue_script(
'care-booking-admin',
CARE_BOOKING_BLOCK_PLUGIN_URL . "admin/js/admin-script{$min_suffix}.js",
['jquery', 'wp-util'],
$version,
true
);
// Optimized localization with minimal data
$localize_data = self::get_optimized_admin_localize_data();
wp_localize_script('care-booking-admin', 'careBookingAjax', $localize_data);
}
/**
* Get optimized admin localization data
*
* @return array Minimal required data
*/
private static function get_optimized_admin_localize_data()
{
return [
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('care_booking_admin'),
'strings' => [
'error' => __('An error occurred. Please try again.', 'care-booking-block'),
'success_update' => __('Updated successfully.', 'care-booking-block'),
'success_bulk' => __('Bulk operation completed.', 'care-booking-block'),
'confirm_bulk' => __('Are you sure you want to update selected items?', 'care-booking-block')
]
];
}
/**
* Add async/defer attributes to scripts for better performance
*
* @param string $tag Script tag
* @param string $handle Script handle
* @param string $src Script source
* @return string Modified script tag
*/
public static function add_script_attributes($tag, $handle, $src)
{
// Add async to non-critical frontend scripts
if ($handle === 'care-booking-frontend' && !is_admin()) {
// Only add async if jQuery is already loaded or loading
if (wp_script_is('jquery', 'done') || wp_script_is('jquery', 'to_do')) {
$tag = str_replace(' src', ' async src', $tag);
}
}
return $tag;
}
/**
* Preload critical assets for better performance
*/
public static function preload_critical_assets()
{
if (!self::should_load_frontend_assets()) {
return;
}
$version = self::get_asset_version();
$min_suffix = self::get_min_suffix();
// Preload critical CSS
$css_url = CARE_BOOKING_BLOCK_PLUGIN_URL . "public/css/frontend{$min_suffix}.css?ver={$version}";
echo "<link rel='preload' href='{$css_url}' as='style' onload=\"this.onload=null;this.rel='stylesheet'\">\n";
// Fallback for browsers that don't support preload
echo "<noscript><link rel='stylesheet' href='{$css_url}'></noscript>\n";
}
/**
* Optimize script source URLs
*
* @param string $src Script source
* @param string $handle Script handle
* @return string Optimized source
*/
public static function optimize_script_src($src, $handle)
{
// Add cache busting and CDN optimization for Care Booking scripts
if (strpos($handle, 'care-booking') === 0) {
// Add integrity checking for security
if (!is_admin() && defined('CARE_BOOKING_ENABLE_SRI') && CARE_BOOKING_ENABLE_SRI) {
add_filter('script_loader_tag', function($tag, $h, $s) use ($handle, $src) {
if ($h === $handle) {
$integrity = self::get_file_integrity($src);
if ($integrity) {
$tag = str_replace('></script>', " integrity='{$integrity}' crossorigin='anonymous'></script>", $tag);
}
}
return $tag;
}, 10, 3);
}
}
return $src;
}
/**
* Optimize style source URLs
*
* @param string $src Style source
* @param string $handle Style handle
* @return string Optimized source
*/
public static function optimize_style_src($src, $handle)
{
// Add performance optimizations for Care Booking styles
if (strpos($handle, 'care-booking') === 0) {
// Ensure proper media attribute for optimal loading
add_filter('style_loader_tag', function($html, $h, $href, $media) use ($handle) {
if ($h === $handle && $media === 'all') {
// Add performance attributes
$html = str_replace("media='all'", "media='all' data-optimized='true'", $html);
}
return $html;
}, 10, 4);
}
return $src;
}
/**
* Get asset version with intelligent cache busting
*
* @return string Asset version
*/
private static function get_asset_version()
{
$versions = get_transient(self::ASSET_VERSION_KEY);
if ($versions === false) {
$versions = self::generate_asset_versions();
set_transient(self::ASSET_VERSION_KEY, $versions, self::ASSET_CACHE_DURATION);
}
return $versions['global'] ?? CARE_BOOKING_BLOCK_VERSION;
}
/**
* Generate asset versions based on file modification times
*
* @return array Asset versions
*/
private static function generate_asset_versions()
{
$versions = ['global' => CARE_BOOKING_BLOCK_VERSION];
$asset_files = [
'frontend_css' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/css/frontend.css',
'frontend_js' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'public/js/frontend.js',
'admin_css' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/css/admin-style.css',
'admin_js' => CARE_BOOKING_BLOCK_PLUGIN_DIR . 'admin/js/admin-script.js'
];
foreach ($asset_files as $key => $file) {
if (file_exists($file)) {
$versions[$key] = filemtime($file);
}
}
// Generate global version from all file versions
$versions['global'] = md5(serialize($versions));
return $versions;
}
/**
* Get minification suffix based on environment
*
* @return string Empty string or '.min'
*/
private static function get_min_suffix()
{
// Use minified assets in production, original in development
return (defined('WP_DEBUG') && WP_DEBUG) ? '' : '.min';
}
/**
* Check if frontend assets should be loaded
*
* @return bool True if should load
*/
private static function should_load_frontend_assets()
{
global $post;
// Load on pages with KiviCare content
if ($post && (
has_shortcode($post->post_content, 'kivicare') ||
has_block('kivicare/booking', $post->post_content)
)) {
return true;
}
// Load on specific templates
$template = get_page_template_slug();
if (in_array($template, ['page-booking.php', 'page-appointment.php'])) {
return true;
}
return false;
}
/**
* Check if current admin page is Care Booking related
*
* @param string $hook Admin page hook
* @return bool True if Care Booking admin page
*/
private static function is_care_booking_admin_page($hook)
{
$care_booking_pages = [
'tools_page_care-booking-control',
'admin_page_care-booking-settings'
];
return in_array($hook, $care_booking_pages);
}
/**
* Get file integrity hash for Subresource Integrity
*
* @param string $file_url File URL
* @return string|null Integrity hash
*/
private static function get_file_integrity($file_url)
{
// Convert URL to file path
$file_path = str_replace(
CARE_BOOKING_BLOCK_PLUGIN_URL,
CARE_BOOKING_BLOCK_PLUGIN_DIR,
$file_url
);
if (file_exists($file_path)) {
$hash = hash('sha384', file_get_contents($file_path), true);
return 'sha384-' . base64_encode($hash);
}
return null;
}
/**
* Output combined assets for maximum performance
*/
public static function output_combined_assets()
{
// Only combine assets if not in debug mode
if (defined('WP_DEBUG') && WP_DEBUG) {
return;
}
// This would combine multiple CSS/JS files into single requests
// For now, we rely on the individual optimizations above
self::output_performance_markers();
}
/**
* Output performance markers for monitoring
*/
private static function output_performance_markers()
{
if (defined('WP_DEBUG') && WP_DEBUG) {
echo "\n<!-- Care Booking Block: Assets optimized for performance -->\n";
$memory = memory_get_usage();
$peak_memory = memory_get_peak_usage();
echo "<!-- Memory Usage: " . size_format($memory) . " | Peak: " . size_format($peak_memory) . " -->\n";
}
}
/**
* Generate minified CSS from source files
*
* @param string $source_file Source CSS file
* @param string $output_file Output minified file
* @return bool Success status
*/
public static function generate_minified_css($source_file, $output_file)
{
if (!file_exists($source_file)) {
return false;
}
$css = file_get_contents($source_file);
$minified_css = self::minify_css($css);
return file_put_contents($output_file, $minified_css) !== false;
}
/**
* Generate minified JavaScript from source files
*
* @param string $source_file Source JS file
* @param string $output_file Output minified file
* @return bool Success status
*/
public static function generate_minified_js($source_file, $output_file)
{
if (!file_exists($source_file)) {
return false;
}
$js = file_get_contents($source_file);
$minified_js = self::minify_js($js);
return file_put_contents($output_file, $minified_js) !== false;
}
/**
* Minify CSS content
*
* @param string $css CSS content
* @return string Minified CSS
*/
public static function minify_css($css)
{
// Remove comments
$css = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $css);
// Remove whitespace
$css = str_replace(["\r\n", "\r", "\n", "\t"], '', $css);
// Remove extra spaces
$css = preg_replace('/\s+/', ' ', $css);
// Remove spaces around specific characters
$css = str_replace(['; ', ' {', '{ ', ' }', '} ', ': ', ', ', ' ,'], [';', '{', '{', '}', '}', ':', ',', ','], $css);
// Remove trailing semicolon before }
$css = str_replace(';}', '}', $css);
return trim($css);
}
/**
* Basic JavaScript minification
*
* @param string $js JavaScript content
* @return string Minified JavaScript
*/
public static function minify_js($js)
{
// Basic minification - remove comments and extra whitespace
// Note: For production, consider using a proper JS minifier
// Remove single-line comments (but preserve URLs)
$js = preg_replace('#(?<!:)//.*#', '', $js);
// Remove multi-line comments
$js = preg_replace('#/\*.*?\*/#s', '', $js);
// Remove extra whitespace
$js = preg_replace('/\s+/', ' ', $js);
// Remove spaces around operators and punctuation
$js = str_replace([' = ', ' + ', ' - ', ' * ', ' / ', ' { ', ' } ', ' ( ', ' ) ', ' [ ', ' ] ', ' ; ', ' , '],
['=', '+', '-', '*', '/', '{', '}', '(', ')', '[', ']', ';', ','], $js);
return trim($js);
}
/**
* Build minified assets for production
*/
public static function build_production_assets()
{
$assets = [
'admin-style.css' => 'admin/css/admin-style.min.css',
'admin-script.js' => 'admin/js/admin-script.min.js',
'frontend.css' => 'public/css/frontend.min.css',
'frontend.js' => 'public/js/frontend.min.js'
];
$results = [];
foreach ($assets as $source => $target) {
$source_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . str_replace('.min', '', $target);
$target_path = CARE_BOOKING_BLOCK_PLUGIN_DIR . $target;
$extension = pathinfo($source, PATHINFO_EXTENSION);
if ($extension === 'css') {
$results[$source] = self::generate_minified_css($source_path, $target_path);
} elseif ($extension === 'js') {
$results[$source] = self::generate_minified_js($source_path, $target_path);
}
}
return $results;
}
}
// Initialize asset optimizer
Care_Booking_Asset_Optimizer::init();