PluginProbe
Blocks CSS: CSS Editor for Gutenberg Blocks / 3.2.0
Blocks CSS: CSS Editor for Gutenberg Blocks v3.2.0
3.2.5 3.2.4 3.2.2 3.2.1 3.2.0 3.1.11 3.1.10 trunk 1.0.0 1.0.1 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.2 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.10 2.0.11 All 100 releases
blocks-css / class-blocks-css.php

class-blocks-css.php in Blocks CSS: CSS Editor for Gutenberg Blocks 3.2.0, at class-blocks-css.php

300 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class for CSS logic.
4 *
5 * @package ThemeIsle
6 */
7
8 namespace ThemeIsle\GutenbergBlocks;
9
10 /**
11 * Class Blocks_CSS.
12 */
13 class Blocks_CSS {
14
15 /**
16 * The main instance var.
17 *
18 * @var Blocks_CSS|null
19 */
20 public static $instance = null;
21
22 /**
23 * Initialize the class
24 */
25 public function init() {
26 if ( ! defined( 'BLOCKS_CSS_URL' ) ) {
27 define( 'BLOCKS_CSS_URL', OTTER_BLOCKS_URL );
28 define( 'BLOCKS_CSS_PATH', OTTER_BLOCKS_PATH );
29 define( 'BLOCKS_CSS_OTTER', true );
30 }
31
32 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_assets' ), 1 );
33 add_action( 'wp_head', array( $this, 'render_server_side_css' ) );
34 add_action( 'wp_loaded', array( $this, 'add_attributes_to_blocks' ) );
35 add_filter( 'otter_blocks_css', array( $this, 'add_css_to_otter' ) );
36 }
37
38 /**
39 * Load Gutenberg assets.
40 *
41 * @since 1.0.0
42 * @access public
43 */
44 public function enqueue_editor_assets() {
45 $current_screen = get_current_screen();
46
47 if ( 'widgets' === $current_screen->base || 'customize' === $current_screen->base ) {
48 return;
49 }
50
51 wp_enqueue_code_editor( array( 'type' => 'text/css' ) );
52
53 wp_add_inline_script(
54 'wp-codemirror',
55 'window.CodeMirror = wp.CodeMirror;'
56 );
57
58 $asset_file = include BLOCKS_CSS_PATH . '/build/css/index.asset.php';
59
60 if ( defined( 'OTTER_BLOCKS_VERSION' ) ) {
61 array_push( $asset_file['dependencies'], 'otter-blocks' );
62 }
63
64 wp_enqueue_script(
65 'otter-css',
66 BLOCKS_CSS_URL . 'build/css/index.js',
67 array_merge( $asset_file['dependencies'], array( 'code-editor', 'csslint' ) ),
68 $asset_file['version'],
69 true
70 );
71
72 wp_localize_script(
73 'otter-css',
74 'blocksCSS',
75 array(
76 'hasOtter' => defined( 'OTTER_BLOCKS_VERSION' ),
77 'installOtter' => wp_nonce_url(
78 add_query_arg(
79 array(
80 'action' => 'install-plugin',
81 'plugin' => 'otter-blocks',
82 ),
83 admin_url( 'update.php' )
84 ),
85 'install-plugin_otter-blocks'
86 ),
87 )
88 );
89
90 wp_set_script_translations( 'otter-css', defined( 'BLOCKS_CSS_OTTER' ) ? 'otter-blocks' : 'blocks-css' );
91
92 wp_enqueue_style(
93 'otter-css',
94 BLOCKS_CSS_URL . 'build/css/index.css',
95 array( 'code-editor' ),
96 $asset_file['version']
97 );
98 }
99
100 /**
101 * Render server-side CSS
102 *
103 * @since 1.0.0
104 * @access public
105 */
106 public function render_server_side_css() {
107 if ( function_exists( 'has_blocks' ) && has_blocks( get_the_ID() ) ) {
108 global $post;
109
110 if ( ! is_object( $post ) ) {
111 return;
112 }
113
114 $content = '';
115
116 if (
117 ! defined( 'OTTER_BLOCKS_VERSION' ) &&
118 get_queried_object() === null &&
119 function_exists( 'wp_is_block_theme' ) &&
120 wp_is_block_theme() &&
121 current_theme_supports( 'block-templates' )
122 ) {
123 global $_wp_current_template_content;
124
125 $slugs = array();
126 $template_blocks = parse_blocks( $_wp_current_template_content );
127
128 foreach ( $template_blocks as $template_block ) {
129 if ( 'core/template-part' === $template_block['blockName'] ) {
130 $slugs[] = $template_block['attrs']['slug'];
131 }
132 }
133
134 $templates_parts = get_block_templates( array( 'slug__in' => $slugs ), 'wp_template_part' );
135
136 foreach ( $templates_parts as $templates_part ) {
137 if ( ! empty( $templates_part->content ) && ! empty( $templates_part->slug ) && in_array( $templates_part->slug, $slugs ) ) {
138 $content .= $templates_part->content;
139 }
140 }
141
142 $content .= $_wp_current_template_content;
143 } else {
144 $content = $post->post_content;
145 }
146
147 $blocks = parse_blocks( $content );
148
149 if ( ! is_array( $blocks ) || empty( $blocks ) ) {
150 return;
151 }
152
153 $css = $this->cycle_through_blocks( $blocks, $post->ID );
154
155 if ( empty( $css ) ) {
156 return;
157 }
158
159 $style = "\n" . '<style type="text/css" media="all">' . "\n";
160 $style .= $css;
161 $style .= "\n" . '</style>' . "\n";
162
163 echo $style; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
164 }
165 }
166
167 /**
168 * Cycle through Blocks
169 *
170 * @param array $inner_blocks Array of blocks.
171 * @param int $id Post ID.
172 *
173 * @since 1.0.0
174 * @access public
175 */
176 public function cycle_through_blocks( $inner_blocks, $id ) {
177 $style = '';
178
179 foreach ( $inner_blocks as $block ) {
180 $file_name = get_post_meta( $id, '_themeisle_gutenberg_block_stylesheet', true );
181 $render_css = empty( $file_name ) || strpos( $file_name, 'post-v2' ) === false;
182
183 if ( $render_css && isset( $block['attrs'] ) ) {
184 if ( isset( $block['attrs']['hasCustomCSS'] ) && isset( $block['attrs']['customCSS'] ) ) {
185 $style .= $block['attrs']['customCSS'];
186 }
187 }
188
189 if ( 'core/block' === $block['blockName'] && ! empty( $block['attrs']['ref'] ) ) {
190 $reusable_block = get_post( $block['attrs']['ref'] );
191
192 if ( ! $reusable_block || 'wp_block' !== $reusable_block->post_type ) {
193 return '';
194 }
195
196 if ( 'publish' !== $reusable_block->post_status || ! empty( $reusable_block->post_password ) ) {
197 return '';
198 }
199
200 $blocks = parse_blocks( $reusable_block->post_content );
201
202 $style .= $this->cycle_through_blocks( $blocks, $reusable_block->ID );
203 }
204
205 if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
206 $style .= $this->cycle_through_blocks( $block['innerBlocks'], $id );
207 }
208 }
209
210 return $style;
211 }
212
213 /**
214 * Adds the `hasCustomCSS` and `customCSS` attributes to all blocks, to avoid `Invalid parameter(s): attributes`
215 * error in Gutenberg.
216 *
217 * @since 1.0.3
218 * @access public
219 */
220 public function add_attributes_to_blocks() {
221 $registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
222
223 foreach ( $registered_blocks as $block ) {
224 $block->attributes['hasCustomCSS'] = array(
225 'type' => 'boolean',
226 'default' => false,
227 );
228
229 $block->attributes['customCSS'] = array(
230 'type' => 'string',
231 'default' => '',
232 );
233 }
234 }
235
236 /**
237 * Append Block CSS to Otter's CSS file.
238 *
239 * @param array $block Block.
240 *
241 * @since 1.1.4
242 * @access public
243 */
244 public function add_css_to_otter( $block ) {
245 $style = '';
246 if ( isset( $block['attrs'] ) ) {
247 if ( isset( $block['attrs']['hasCustomCSS'] ) && isset( $block['attrs']['customCSS'] ) ) {
248 $style .= $block['attrs']['customCSS'];
249 }
250 }
251
252 return $style;
253 }
254
255 /**
256 * The instance method for the static class.
257 * Defines and returns the instance of the static class.
258 *
259 * @static
260 * @since 1.0.0
261 * @access public
262 * @return Blocks_CSS
263 */
264 public static function instance() {
265 if ( is_null( self::$instance ) ) {
266 self::$instance = new self();
267 self::$instance->init();
268 }
269
270 return self::$instance;
271 }
272
273 /**
274 * Throw error on object clone
275 *
276 * The whole idea of the singleton design pattern is that there is a single
277 * object therefore, we don't want the object to be cloned.
278 *
279 * @access public
280 * @since 1.0.0
281 * @return void
282 */
283 public function __clone() {
284 // Cloning instances of the class is forbidden.
285 _doing_it_wrong( __FUNCTION__, 'Cheatin&#8217; huh?', '1.0.0' );
286 }
287
288 /**
289 * Disable unserializing of the class
290 *
291 * @access public
292 * @since 1.0.0
293 * @return void
294 */
295 public function __wakeup() {
296 // Unserializing instances of the class is forbidden.
297 _doing_it_wrong( __FUNCTION__, 'Cheatin&#8217; huh?', '1.0.0' );
298 }
299 }
300