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