Responsive breakpoints CSS -> Helpers * */ if ( ! defined( 'ABSPATH' ) ) exit; function tbkkt_responsive_breakpoints_css_get_module_path(): string { return trailingslashit( dirname( __FILE__ ) ); } /** * Absolute directory under uploads where generated breakpoint CSS is stored (no trailing slash) */ function tbkkt_responsive_breakpoints_css_get_generated_base_path(): string { if ( ! defined( 'TBKKT_GENERATED_CSS_UPLOADS_DIRNAME' ) ) return ''; $upload = wp_upload_dir( null, false ); if ( ! empty( $upload['error'] ) || empty( $upload['basedir'] ) ) : return ''; endif; return trailingslashit( $upload['basedir'] ) . TBKKT_GENERATED_CSS_UPLOADS_DIRNAME; } /** * Public URL directory for generated CSS (no trailing slash) */ function tbkkt_responsive_breakpoints_css_get_generated_base_url(): string { if ( ! defined( 'TBKKT_GENERATED_CSS_UPLOADS_DIRNAME' ) ) return ''; $upload = wp_upload_dir( null, false ); if ( ! empty( $upload['error'] ) || empty( $upload['baseurl'] ) ) : return ''; endif; return trailingslashit( $upload['baseurl'] ) . TBKKT_GENERATED_CSS_UPLOADS_DIRNAME; } function tbkkt_responsive_breakpoints_css_is_custom_breakpoints_enabled(): bool { if ( ! function_exists( 'tbkkt_settings_get' ) ) return false; $key = tbkkt_responsive_breakpoints_css_get_option_key(); $all = tbkkt_settings_get(); return ! empty( $all[ $key ] ) && is_array( $all[ $key ] ) && ! empty( $all[ $key ]['enabled'] ); } /** * URL and version for wp_register_style: uploads copy when custom breakpoints are on and the file exists; else bundled plugin asset */ function tbkkt_responsive_breakpoints_css_get_resolved_style_registration( string $basename ): array { $basename = trim( $basename ); if ( $basename === '' ) : $basename = 'style.css'; endif; // Find source path in manifest $manifest = tbkkt_responsive_breakpoints_css_get_generated_file_pairs(); $source_relative = ''; foreach ( $manifest as $pair ) : if ( isset( $pair['output_name'] ) && $pair['output_name'] === $basename ) : $source_relative = isset( $pair['source'] ) ? $pair['source'] : ''; break; endif; endforeach; // Fallback: assume assets/css/{basename} if not in manifest if ( $source_relative === '' ) : $source_relative = 'assets/css/' . basename( $basename ); endif; $plugin_path = TBKKT_PLUGIN_PATH . $source_relative; $plugin_url = TBKKT_PLUGIN_URL . $source_relative; $version = file_exists( $plugin_path ) ? (int) filemtime( $plugin_path ) : (int) TBKKT_PLUGIN_VERSION; if ( ! tbkkt_responsive_breakpoints_css_is_custom_breakpoints_enabled() ) : return array( 'url' => $plugin_url, 'version' => $version, ); endif; $dir = tbkkt_responsive_breakpoints_css_get_generated_base_path(); if ( $dir === '' ) : return array( 'url' => $plugin_url, 'version' => $version, ); endif; $gen_path = $dir . '/' . $basename; if ( is_readable( $gen_path ) ) : return array( 'url' => trailingslashit( tbkkt_responsive_breakpoints_css_get_generated_base_url() ) . $basename, 'version' => (int) filemtime( $gen_path ), ); endif; return array( 'url' => $plugin_url, 'version' => $version, ); } /** * WordPress filesystem API for generated uploads cleanup */ function tbkkt_responsive_breakpoints_css_get_filesystem() { global $wp_filesystem; if ( ! empty( $wp_filesystem ) ) return $wp_filesystem; if ( ! function_exists( 'WP_Filesystem' ) ) : require_once ABSPATH . 'wp-admin/includes/file.php'; endif; WP_Filesystem(); if ( empty( $wp_filesystem ) ) : return null; endif; return $wp_filesystem; } function tbkkt_responsive_breakpoints_css_remove_directory( string $path ): bool { $filesystem = tbkkt_responsive_breakpoints_css_get_filesystem(); if ( null === $filesystem ) return false; return $filesystem->rmdir( $path, false ); } /** * Remove generated CSS files from uploads; if the directory is empty or only contains index.php, remove those too */ function tbkkt_responsive_breakpoints_css_delete_generated_uploads(): void { $dir = tbkkt_responsive_breakpoints_css_get_generated_base_path(); if ( $dir === '' || ! is_dir( $dir ) ) return; $upload = wp_upload_dir( null, false ); if ( ! empty( $upload['error'] ) || empty( $upload['basedir'] ) ) return; $basedir_real = realpath( $upload['basedir'] ); $dir_real = realpath( $dir ); if ( false === $basedir_real || false === $dir_real ) return; if ( strpos( $dir_real, $basedir_real ) !== 0 ) return; // Delete each file from manifest $manifest = tbkkt_responsive_breakpoints_css_get_generated_file_pairs(); foreach ( $manifest as $pair ) : if ( ! isset( $pair['output_name'] ) ) continue; $name = $pair['output_name']; $file = $dir . '/' . $name; if ( is_file( $file ) && is_readable( $file ) ) : wp_delete_file( $file ); endif; endforeach; // Remove empty subdirectories $subdirs = array( 'container', 'icon' ); foreach ( $subdirs as $subdir ) : $subdir_path = $dir . '/' . $subdir; if ( is_dir( $subdir_path ) ) : $items = scandir( $subdir_path, SCANDIR_SORT_NONE ); if ( false !== $items ) : $names = array_values( array_diff( $items, array( '.', '..' ) ) ); if ( empty( $names ) ) : tbkkt_responsive_breakpoints_css_remove_directory( $subdir_path ); endif; endif; endif; endforeach; // Check if base directory is empty or only has index.php $items = scandir( $dir, SCANDIR_SORT_NONE ); if ( false === $items ) return; $names = array_values( array_diff( $items, array( '.', '..' ) ) ); sort( $names, SORT_STRING ); if ( $names === array() ) : if ( ! tbkkt_responsive_breakpoints_css_remove_directory( $dir ) ) : tbkkt_plugin_log_error( 'tms-block-kit: could not remove empty generated CSS directory under uploads.' ); endif; return; endif; if ( $names === array( 'index.php' ) ) : $index = $dir . '/index.php'; if ( is_file( $index ) ) : wp_delete_file( $index ); endif; if ( ! tbkkt_responsive_breakpoints_css_remove_directory( $dir ) ) : tbkkt_plugin_log_error( 'tms-block-kit: could not remove generated CSS directory under uploads after removing index.php.' ); endif; endif; } /** * Prevent directory listing in uploads subfolder (best-effort) */ function tbkkt_responsive_breakpoints_css_write_uploads_index_if_missing(): void { $dir = tbkkt_responsive_breakpoints_css_get_generated_base_path(); if ( $dir === '' || ! is_dir( $dir ) ) return; $index = trailingslashit( $dir ) . 'index.php'; if ( file_exists( $index ) ) return; $file_put = file_put_contents( $index, '