Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
CSSUtilities
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 11
812
0.00% covered (danger)
0.00%
0 / 1
 get_local_base_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_production_base_url
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_instance
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 enqueue
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
30
 get_asset_content
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 get_inline_css
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 get_base_url
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 conditional_refresh_assets
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 refresh_assets
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 fetch_and_store_asset
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace NewfoldLabs\WP\Module\Patterns;
4
5class CSSUtilities {
6    
7    /**
8     * The single instance of the class.
9     *
10     * @var CSSUtilities|null
11     */
12    private static $instance = null;
13
14    /**
15     * The production base URL.
16     *
17     * @var string
18     */
19    protected static $production_base_url = 'https://patterns.hiive.cloud/cdn';
20
21    /**
22     * The local base URL.
23     *
24     * @var string
25     */
26    protected static $local_base_url = 'http://localhost:8888';
27
28    /**
29     * Get the local base URL.
30     *
31     * @return string
32     */
33    protected static function get_local_base_url() {
34        return defined( 'NFD_WB_LOCAL_BASE_URL' ) ? NFD_WB_LOCAL_BASE_URL : self::$local_base_url;
35    }
36
37    /**
38     * Get the production base URL.
39     *
40     * @return string
41     */
42    protected static function get_production_base_url() {
43        return defined( 'NFD_WB_PRODUCTION_BASE_URL' ) ? NFD_WB_PRODUCTION_BASE_URL : self::$production_base_url;
44    }
45
46    /**
47     * Get the single instance of the class.
48     *
49     * @return CSSUtilities The instance of the class.
50     */
51    public static function get_instance(): CSSUtilities {
52        if ( null === self::$instance ) {
53            self::$instance = new self();
54        }
55        return self::$instance;
56    }
57
58    /**
59     * Constructor.
60     */
61    private function __construct() {
62
63        if ( \is_admin() ) {
64            \add_action( 'enqueue_block_assets', array( $this, 'enqueue' ) );
65        } else {
66            \add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ) );
67        }
68
69        \add_action( 'enqueue_nfd_wonder_blocks_utilities', array( $this, 'enqueue' ) );
70    }
71
72    /**
73     * Enqueue assets used on front-end and back-end.
74     *
75     * @return void
76     */
77    public function enqueue() {
78        // Skip if the current page is the onboarding page to prevent conflicts with the onboarding styling.
79        if ( isset( $_GET['page'] ) && stripos( \sanitize_text_field( $_GET['page'] ), 'nfd-onboarding' ) === 0 ) {
80            return;
81        }
82
83        // Refresh assets if 24 hours have passed since the last refresh.
84        $this->conditional_refresh_assets();
85        
86        $css_content = $this->get_asset_content( 'utilities_css' );
87        $js_content  = $this->get_asset_content( 'utilities_js' );
88        
89        if ( $css_content ) {
90            \wp_register_style( 'nfd-wonder-blocks-utilities', false );
91            \wp_enqueue_style( 'nfd-wonder-blocks-utilities');
92            \wp_add_inline_style( 'nfd-wonder-blocks-utilities', $css_content );
93        } else {
94            \wp_enqueue_style(
95                'nfd-wonder-blocks-utilities',
96                constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.css',
97                array(),
98                constant( 'NFD_WONDER_BLOCKS_VERSION' )
99            );
100        }
101        
102        if ( $js_content ) {
103            \wp_register_script( 'nfd-wonder-blocks-utilities', false );
104            \wp_enqueue_script( 'nfd-wonder-blocks-utilities' );
105            \wp_add_inline_script( 'nfd-wonder-blocks-utilities', $js_content );
106        } else {
107            \wp_enqueue_script(
108                'nfd-wonder-blocks-utilities',
109                constant( 'NFD_WONDER_BLOCKS_URL' ) . '/assets/build/utilities.js',
110                array(),
111                constant( 'NFD_WONDER_BLOCKS_VERSION' )
112            );
113        }
114
115        \wp_add_inline_style( 'nfd-wonder-blocks-utilities', $this->get_inline_css() );
116    }
117    
118    /**
119     * Get the content of an asset.
120     *
121     * @param string $asset The asset to get the content of.
122     * @return string The content of the asset.
123     */
124    private function get_asset_content( string $option_key ) {
125        $sanitized_key = \sanitize_key( 'nfd_' . $option_key );
126        return \wp_unslash( \get_option( $sanitized_key, false ) );
127    }
128    
129    /**
130     * Generates inline CSS based on the current active theme.
131     *
132     * This function returns a set of CSS variables that are used to style the front-end 
133     * and editor based on the active theme. Different themes may define their own color, 
134     * font, and spacing presets, which are reflected in the generated CSS.
135     *
136     * @return string The generated CSS.
137     */
138    private function get_inline_css() {
139        $theme = \wp_get_theme()->get_template();
140        $css   = '';
141
142        if ( 'bluehost-blueprint' === $theme ) {
143            $css = "body, .editor-styles-wrapper {
144                --wndb--color--primary: var(--wp--preset--color--accent-2);
145                --wndb--color--secondary: var(--wp--preset--color--accent-5);
146                --wndb--color--tertiary: var(--wp--preset--color--accent-3);
147                --wndb--color--body: var(--wp--preset--color--base);
148                --wndb--color--text: var(--wp-preset--color--contrast);
149                --wndb--color--text--contrast: var(--wp--preset--color--contrast);
150                --wndb--color--text--faded: color-mix(in srgb, var(--wp--preset--color--contrast), transparent 20%);
151                --wndb--color--surface: var(--wp--preset--color--base-midtone);
152
153                --wndb--text--sm: var(--wp--preset--font-size--small);
154
155                --wndb--p--xs: var(--wp--preset--spacing--20);
156                --wndb--p--sm: var(--wp--preset--spacing--40);
157                --wndb--p--md: var(--wp--preset--spacing--60);
158                --wndb--p--lg: var(--wp--preset--spacing--80);
159
160                --wndb--max-w--prose: 650px;
161            }";
162        }
163
164        if ( 'yith-wonder' === $theme ) {
165            $css = "body, .editor-styles-wrapper {
166                --wndb--color--primary: var(--wp--preset--color--primary);
167                --wndb--color--secondary: var(--wp--preset--color--secondary);
168                --wndb--color--body: var(--wp--preset--color--base);
169                --wndb--p: var(--wp--preset--spacing--40);
170                --wndb--text--sm: var(--wp--preset--font-size--x-small);
171                --wndb--text--md: var(--wp--preset--font-size--normal);
172            }";
173        }
174        
175        return $css;
176    }
177
178    /**
179     * Get the base URL
180     * 
181     * @return string The base URL.
182     */
183    public function get_base_url(): string {
184        if ( defined( 'NFD_DATA_WB_DEV_MODE' ) && constant( 'NFD_DATA_WB_DEV_MODE' ) ) {
185            return self::get_local_base_url();
186        }
187
188        return self::get_production_base_url();
189    }
190
191    /**
192     * Conditionally refresh CSS and JS assets from remote sources if 24 hours have passed.
193     *
194     * @return void
195     */
196    public function conditional_refresh_assets() {
197        $last_refresh = \get_option( 'nfd_utilities_last_refresh_time', 0 );
198        $current_time = time();
199        
200        if ( ( $current_time - $last_refresh ) > DAY_IN_SECONDS || ( defined( 'NFD_DATA_WB_DEV_MODE' ) && constant( 'NFD_DATA_WB_DEV_MODE' ) ) ) {
201            $this->refresh_assets();
202            \update_option( 'nfd_utilities_last_refresh_time', $current_time );
203        }
204    }
205
206    /**
207     * Refresh CSS and JS assets from remote sources.
208     * This method can be manually triggered by other actions or hooks as needed.
209     *
210     * @return void
211     */
212    public function refresh_assets() {
213        $this->fetch_and_store_asset( '/assets/css/utilities.css', 'utilities_css' );
214        $this->fetch_and_store_asset( '/assets/js/utilities.js', 'utilities_js' );
215    }
216
217    /**
218     * Fetch and store the asset content in the database with minification.
219     *
220     * @param string $path The path of the remote asset.
221     * @param string $option_key The option key to store the content.
222     *
223     * @return void
224     */
225    private function fetch_and_store_asset( string $path, string $option_key ) {
226        $base_url = $this->get_base_url();
227        $url = \esc_url_raw( $base_url . $path );
228
229        $response = \wp_remote_get( $url );
230        
231        if ( ! \is_wp_error( $response ) && 200 === \wp_remote_retrieve_response_code( $response ) ) {
232            $content = \wp_remote_retrieve_body( $response );
233            $sanitized_key = \sanitize_key( 'nfd_' . $option_key );
234            \update_option( $sanitized_key, \wp_slash( $content ) );
235        }
236    }
237}