class-gutenberg-custom-css.php (5804B)
1 <?php 2 /** 3 * Load CSS logic. 4 * 5 * @package gutenberg-css 6 */ 7 8 namespace ReduxTemplates; 9 10 if ( ! class_exists( '\ReduxTemplates\Gutenberg_Custom_CSS' ) ) { 11 12 /** 13 * Class GutenbergCSS. 14 */ 15 class Gutenberg_Custom_CSS { 16 17 /** 18 * The main instance var. 19 * 20 * @var Gutenberg_Custom_CSS 21 */ 22 public static $instance = null; 23 24 /** 25 * Initialize the class 26 */ 27 public function init() { 28 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_assets' ) ); 29 add_action( 'wp_head', array( $this, 'render_server_side_css' ) ); 30 add_action( 'wp_loaded', array( $this, 'add_attributes_to_blocks' ) ); 31 add_action( 'plugins_loaded', array( $this, 'remove_themeisle_css' ), 99 ); 32 } 33 34 /** 35 * Remove ThemeIsle GutenbergCSS. 36 * 37 * @since 4.0.0 38 * @access public 39 */ 40 public function remove_themeisle_css() { 41 if ( class_exists( '\ThemeIsle\GutenbergCSS' ) ) { 42 $instance = \ThemeIsle\GutenbergCSS::instance(); 43 remove_action( 44 'enqueue_block_editor_assets', 45 array( 46 $instance, 47 'enqueue_editor_assets', 48 ) 49 ); 50 remove_action( 'wp_head', array( $instance, 'render_server_side_css' ) ); 51 remove_action( 'wp_loaded', array( $instance, 'add_attributes_to_blocks' ) ); 52 } 53 } 54 55 /** 56 * Load Gutenberg assets. 57 * 58 * @since 1.0.0 59 * @access public 60 */ 61 public function enqueue_editor_assets() { 62 63 wp_enqueue_code_editor( array( 'type' => 'text/css' ) ); 64 65 wp_add_inline_script( 66 'wp-codemirror', 67 'window.CodeMirror = wp.CodeMirror;' 68 ); 69 70 wp_set_script_translations( 'redux-gutenberg-css', 'redux-framework' ); 71 72 } 73 74 /** 75 * Parse Blocks for Gutenberg and WordPress 5.0 76 * 77 * @param string $content Content to parse. 78 * 79 * @since 1.0.0 80 * @access public 81 * @return string 82 */ 83 public function parse_blocks( $content ) { 84 if ( ! function_exists( 'parse_blocks' ) ) { 85 return gutenberg_parse_blocks( $content ); 86 } else { 87 return parse_blocks( $content ); 88 } 89 } 90 91 /** 92 * Render server-side CSS 93 * 94 * @since 1.0.0 95 * @access public 96 */ 97 public function render_server_side_css() { 98 if ( function_exists( 'has_blocks' ) && has_blocks( get_the_ID() ) ) { 99 global $post; 100 101 if ( ! is_object( $post ) ) { 102 return; 103 } 104 105 $blocks = $this->parse_blocks( $post->post_content ); 106 107 if ( ! is_array( $blocks ) || empty( $blocks ) ) { 108 return; 109 } 110 111 $style = "\n" . '<style type="text/css" media="all">' . "\n"; 112 $style .= $this->cycle_through_blocks( $blocks ); 113 $style .= "\n" . '</style>' . "\n"; 114 115 echo $style; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 116 } 117 } 118 119 /** 120 * Cycle thorugh Blocks 121 * 122 * @param array $inner_blocks Array of blocks. 123 * @since 1.0.0 124 * @access public 125 * @return string 126 */ 127 public function cycle_through_blocks( $inner_blocks ) { 128 $style = ''; 129 foreach ( $inner_blocks as $block ) { 130 if ( isset( $block['attrs'] ) ) { 131 if ( isset( $block['attrs']['hasCustomCSS'] ) && isset( $block['attrs']['customCSS'] ) ) { 132 $style .= $block['attrs']['customCSS']; 133 } 134 } 135 136 if ( 'core/block' === $block['blockName'] && ! empty( $block['attrs']['ref'] ) ) { 137 $reusable_block = get_post( $block['attrs']['ref'] ); 138 139 if ( ! $reusable_block || 'wp_block' !== $reusable_block->post_type ) { 140 return; 141 } 142 143 if ( 'publish' !== $reusable_block->post_status || ! empty( $reusable_block->post_password ) ) { 144 return; 145 } 146 147 $blocks = $this->parse_blocks( $reusable_block->post_content ); 148 149 $style .= $this->cycle_through_blocks( $blocks ); 150 } 151 152 if ( isset( $block['innerBlocks'] ) && ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) { 153 $style .= $this->cycle_through_blocks( $block['innerBlocks'] ); 154 } 155 } 156 return $style; 157 } 158 159 /** 160 * Adds the `hasCustomCSS` and `customCSS` attributes to all blocks, to avoid `Invalid parameter(s): attributes` 161 * error in Gutenberg. 162 * 163 * @since 1.0.3 164 * @access public 165 */ 166 public function add_attributes_to_blocks() { 167 $registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered(); 168 169 foreach ( $registered_blocks as $name => $block ) { 170 $block->attributes['hasCustomCSS'] = array( 171 'type' => 'boolean', 172 'default' => false, 173 ); 174 175 $block->attributes['customCSS'] = array( 176 'type' => 'string', 177 'default' => '', 178 ); 179 } 180 } 181 182 /** 183 * Method to return path to child class in a Reflective Way. 184 * 185 * @since 1.0.0 186 * @access protected 187 * @return string 188 */ 189 protected function get_dir() { 190 return dirname( __FILE__ ); 191 } 192 193 /** 194 * The instance method for the static class. 195 * Defines and returns the instance of the static class. 196 * 197 * @static 198 * @since 1.0.0 199 * @access public 200 * @return GutenbergCSS 201 */ 202 public static function instance() { 203 if ( is_null( self::$instance ) ) { 204 self::$instance = new self(); 205 self::$instance->init(); 206 } 207 208 return self::$instance; 209 } 210 211 /** 212 * Throw error on object clone 213 * 214 * The whole idea of the singleton design pattern is that there is a single 215 * object therefore, we don't want the object to be cloned. 216 * 217 * @access public 218 * @since 1.0.0 219 * @return void 220 */ 221 public function __clone() { 222 // Cloning instances of the class is forbidden. 223 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'redux-framework' ), '1.0.0' ); 224 } 225 226 /** 227 * Disable unserializing of the class 228 * 229 * @access public 230 * @since 1.0.0 231 * @return void 232 */ 233 public function __wakeup() { 234 // Unserializing instances of the class is forbidden. 235 _doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin’ huh?', 'redux-framework' ), '1.0.0' ); 236 } 237 } 238 }