PluginProbe
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts / trunk
Content Blocks Builder – Create blocks, repeater blocks with carousel, grid, popup layouts vtrunk
2.8.14 2.8.13 2.8.12 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.11 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 trunk 1.0.1 1.0.2 1.1.0 1.1.1 All 147 releases
← All changes | includes/custom-style.php +341 -31 2.8.9 → trunk View file →
@@ -131,10 +131,19 @@
131 131
132 132 // Render settings for carousels.
133 133 add_filter( 'render_block', [ $this, 'render_carousel_settings' ], 30, 3 );
134 134
135 - // Migrate CBB class for old blocks.
136 - add_filter( 'render_block', [ $this, 'migrate_cbb_class' ], 30, 3 );
135 + // Handle migration css class and custom css.
136 + add_filter( 'render_block', [ $this, 'manage_cbb_class' ], 30, 3 );
137 +
138 + // Render steps block data.
139 + add_filter( 'render_block_data', [ $this, 'render_steps_block_data' ], 10, 3 );
140 +
141 + // Render steps blocks.
142 + add_filter( 'render_block', [ $this, 'render_steps_attributes' ], 10, 2 );
143 +
144 + // Sanitize post data before saving to database.
145 + add_filter( 'wp_insert_post_data', [ $this, 'sanitize_post_data' ] );
137 146 }
138 147
139 148 /**
140 149 * Register custom setting fields
@@ -1100,8 +1109,9 @@
1100 1109
1101 1110 /**
1102 1111 * Build transform item: translate, rotate, scale, skew
1103 1112 *
1113 + * @param array $transform_item
1104 1114 * @return string
1105 1115 */
1106 1116 private function build_transform_item( $transform_item ) {
1107 1117 $style = '';
@@ -1392,8 +1402,9 @@
1392 1402 /**
1393 1403 * Build style for accordion border
1394 1404 *
1395 1405 * @param array $args
1406 + * @param array $style_array
1396 1407 * @return string
1397 1408 */
1398 1409 private function build_accordion_border_style( $args, &$style_array ) {
1399 1410 $value = $args['value'] ?? null;
@@ -1434,8 +1445,9 @@
1434 1445 /**
1435 1446 * Build style for accordion radius
1436 1447 *
1437 1448 * @param array $args
1449 + * @param array $style_array
1438 1450 * @return string
1439 1451 */
1440 1452 private function build_accordion_radius_style( $args, &$style_array ) {
1441 1453 $value = $args['value'] ?? null;
@@ -1477,9 +1489,9 @@
1477 1489
1478 1490 /**
1479 1491 * Check whether current block has custom style or not.
1480 1492 *
1481 - * @param [type] $block
1493 + * @param array $block
1482 1494 * @return boolean
1483 1495 */
1484 1496 private function get_custom_css_style( $block ) {
1485 1497 // There is no boldblocks value.
@@ -1573,10 +1585,16 @@
1573 1585 return $this->build_thumbnail_background( $background, $block_content, $block, $block_instance );
1574 1586 } elseif ( $media_url ) {
1575 1587 return $this->build_custom_image_background( $background, $block_content, $block, $block_instance );
1576 1588 }
1577 - } elseif ( 'video' === $media_type && $media_url ) {
1578 - return $this->build_video_background( $background, $block_content, $block, $block_instance );
1589 + } elseif ( 'video' === $media_type ) {
1590 + if ( $media_url ) {
1591 + return $this->build_video_background( $background, $block_content, $block, $block_instance );
1592 + }
1593 + } elseif ( 'embed' === $media_type ) {
1594 + if ( $media_url ) {
1595 + return $this->build_embed_background( $background, $block_content, $block, $block_instance );
1596 + }
1579 1597 }
1580 1598
1581 1599 return $block_content;
1582 1600 }
@@ -1969,9 +1987,9 @@
1969 1987 if ( ! $name || ! $duration ) {
1970 1988 return $accumulator;
1971 1989 }
1972 1990
1973 - $delay = $animation['delay'] ?? 0;
1991 + $delay = empty( $animation['delay'] ) ? 0 : $animation['delay'];
1974 1992 $repeat = $animation['repeat'] ?? 1;
1975 1993 $infinite = $animation['infinite'] ?? false;
1976 1994 $timing_function = $animation['timingFunction'] ?? '';
1977 1995 $animation_name = isset( $animation_names[ $name ]['name'] ) ? $animation_names[ $name ]['name'] : $name;
@@ -2153,9 +2171,10 @@
2153 2171 $block_background = sprintf( '<div class="bb:block-background bb:block-background--video"><video src="%1$s" autoplay="autoplay" muted loop playsinline preload="auto" style="%2$s"/></div>', $media['url'], $video_style );
2154 2172
2155 2173 if ( $media['isPausable'] ?? false ) {
2156 2174 $block_class .= ' cbb-has-video-controls';
2157 - $block_background .= '<button class="cbb-play-pause cbb-video-play-pause is-playing"></button>';
2175 + $position_class = ( $media['playPausePosition'] ?? '' ) ? ' is-' . esc_attr( $media['playPausePosition'] ) : '';
2176 + $block_background .= '<button class="cbb-play-pause cbb-video-play-pause is-playing' . $position_class . '"></button>';
2158 2177 }
2159 2178
2160 2179 if ( strpos( $block['innerHTML'] ?? '', $block_class ) === false ) {
2161 2180 $block_content = $this->add_class_to_block( $block_content, $block_class );
@@ -2166,8 +2185,123 @@
2166 2185 return $block_content;
2167 2186 }
2168 2187
2169 2188 /**
2189 + * Build the embed background
2190 + *
2191 + * @param array $background
2192 + * @param string $block_content
2193 + * @param array $block
2194 + * @param WP_Block $block_instance
2195 + * @return string
2196 + */
2197 + private function build_embed_background( $background, $block_content, $block, $block_instance ) {
2198 + $media = $background['embed'] ?? [];
2199 +
2200 + // Invalid data.
2201 + if ( ! is_string( $media['url'] ) ) {
2202 + return $block_content;
2203 + }
2204 +
2205 + $block_background = '';
2206 +
2207 + // Use WordPress's native oEmbed processing (includes caching).
2208 + $oembed_html = wp_oembed_get( $media['url'] );
2209 +
2210 + if ( $oembed_html ) {
2211 + // Extract iframe src from the oEmbed HTML.
2212 + preg_match( '/src=["\']([^"\']+)["\']/', $oembed_html, $src_matches );
2213 + if ( ! empty( $src_matches[1] ) ) {
2214 + $iframe_src = $src_matches[1];
2215 +
2216 + // Detect provider from iframe src URL.
2217 + $lower_src = strtolower( $iframe_src );
2218 + $provider = null;
2219 +
2220 + if ( str_contains( $lower_src, 'youtube.com' ) || str_contains( $lower_src, 'youtu.be' ) ) {
2221 + $provider = 'youtube';
2222 + } elseif ( str_contains( $lower_src, 'vimeo.com' ) ) {
2223 + $provider = 'vimeo';
2224 + } elseif ( str_contains( $lower_src, 'videopress.com' ) ) {
2225 + $provider = 'videopress';
2226 + } elseif ( str_contains( $lower_src, 'wordpress.tv' ) ) {
2227 + $provider = 'wordpress-tv';
2228 + }
2229 +
2230 + // Modify iframe src to add background video parameters based on provider.
2231 + $parsed_url = wp_parse_url( $iframe_src );
2232 + if ( $parsed_url && isset( $parsed_url['host'] ) ) {
2233 + // Parse existing query parameters.
2234 + $query_params = array();
2235 + if ( isset( $parsed_url['query'] ) ) {
2236 + parse_str( $parsed_url['query'], $query_params );
2237 + }
2238 +
2239 + // Add background video parameters based on provider.
2240 + if ( 'youtube' === $provider ) {
2241 + $query_params['autoplay'] = '1';
2242 + $query_params['mute'] = '1';
2243 + $query_params['loop'] = '1';
2244 + $query_params['controls'] = '0';
2245 + $query_params['playsinline'] = '1';
2246 + $query_params['rel'] = '1';
2247 +
2248 + // For loop to work, we need the playlist parameter.
2249 + $path = $parsed_url['path'] ?? '';
2250 + $path_segments = explode( '/', $path );
2251 + $video_id = end( $path_segments );
2252 + if ( $video_id ) {
2253 + $query_params['playlist'] = $video_id;
2254 + }
2255 + } elseif ( 'vimeo' === $provider ) {
2256 + $query_params['autoplay'] = '1';
2257 + $query_params['muted'] = '1';
2258 + $query_params['loop'] = '1';
2259 + $query_params['background'] = '1';
2260 + $query_params['controls'] = '0';
2261 + $query_params['transparent'] = '0';
2262 + } else {
2263 + $query_params['autoplay'] = '1';
2264 + $query_params['loop'] = '1';
2265 + $query_params['muted'] = '1';
2266 + }
2267 +
2268 + // Rebuild the URL with new parameters.
2269 + $iframe_src = $parsed_url['scheme'] . '://' . $parsed_url['host'];
2270 + if ( isset( $parsed_url['path'] ) ) {
2271 + $iframe_src .= $parsed_url['path'];
2272 + }
2273 + if ( ! empty( $query_params ) ) {
2274 + $iframe_src .= '?' . http_build_query( $query_params );
2275 + }
2276 + }
2277 +
2278 + // Build the iframe HTML that will replace the figure.
2279 + $iframe_html = sprintf(
2280 + '<iframe src="%s" title="Background video" frameborder="0" allow="autoplay; fullscreen"></iframe>',
2281 + esc_url( $iframe_src )
2282 + );
2283 +
2284 + $block_background = sprintf( '<div class="bb:block-background bb:block-background--embed">%s</div>', $iframe_html );
2285 + }
2286 + }
2287 +
2288 + if ( ! $block_background ) {
2289 + return $block_content;
2290 + }
2291 +
2292 + $block_class = 'bb:has-background bb:has-background--embed';
2293 + if ( strpos( $block['innerHTML'] ?? '', $block_class ) === false ) {
2294 + $block_content = $this->add_class_to_block( $block_content, $block_class );
2295 + }
2296 +
2297 + $block_content = $this->add_inner_content_to_block( $block_content, $block_background );
2298 +
2299 + return $block_content;
2300 + }
2301 +
2302 +
2303 + /**
2170 2304 * Render block overlay
2171 2305 *
2172 2306 * @param string $block_content
2173 2307 * @param array $block
@@ -2764,9 +2898,9 @@
2764 2898 // Build carousel settings.
2765 2899 $carousel_settings = $post_template->attributes['boldblocks']['carousel'] ?? [];
2766 2900 if ( $carousel_settings ) {
2767 2901 if ( ! $this->block_has_attribute( 'data-carousel-settings', $block_content ) ) {
2768 - $carousel_attr = $this->build_carousel_settings( $carousel_settings, true );
2902 + $carousel_attr = $this->build_carousel_settings( $carousel_settings, true, $post_template->parsed_block, $post_template );
2769 2903
2770 2904 if ( $carousel_attr ) {
2771 2905 $block_content = $this->add_data_to_block( $block_content, 'data-carousel-settings', esc_attr( $carousel_attr ) );
2772 2906 }
@@ -2939,13 +3073,15 @@
2939 3073
2940 3074 /**
2941 3075 * Build a json string of carousel settings
2942 3076 *
2943 - * @param array $carousel_settings
2944 - * @param boolean $exclude_li_role
3077 + * @param array $carousel_settings
3078 + * @param boolean $exclude_li_role
3079 + * @param array $parsed_block
3080 + * @param WP_Block $block_instance
2945 3081 * @return string
2946 3082 */
2947 - private function build_carousel_settings( $carousel_settings, $exclude_li_role = false ) {
3083 + private function build_carousel_settings( $carousel_settings, $exclude_li_role = false, $parsed_block = null, $block_instance = null ) {
2948 3084 // phpcs:disable
2949 3085 $dataset = [];
2950 3086
2951 3087 // Speed.
@@ -3039,8 +3175,14 @@
3039 3175
3040 3176 if ( in_array($effect, $slidesPerViewDependencies, true ) ) {
3041 3177 $dataset['slidesPerView'] = 1;
3042 3178 } else {
3179 + // centeredSlides.
3180 + $dataset['centeredSlides'] = $carousel_settings['centeredSlides'] ?? false;
3181 + if ($dataset['centeredSlides'] && $effect === 'slide' && ($carousel_settings['centeredSlidesSettings']['enable'] ?? '')) {
3182 + $dataset['centeredSlidesSettings'] = $carousel_settings['centeredSlidesSettings'];
3183 + }
3184 +
3043 3185 $slidesPerView = $this->carousel_refine_slides_per_view( $carousel_settings['slidesPerView'] ?? 1 );
3044 3186 $slidesPerGroup = absint( $carousel_settings['slidesPerGroup'] ?? 0 );
3045 3187
3046 3188 if ( $slidesPerView ) {
@@ -3125,17 +3267,17 @@
3125 3267 'slidesPerGroup' => $slidesPerGroup ? $slidesPerGroup : 1,
3126 3268 ],
3127 3269 ];
3128 3270 }
3271 +
3272 + // Reset centeredSlides
3273 + if ( ! ( $slidesPerView > 1 || 'auto' === $slidesPerView ) ) {
3274 + unset( $dataset['centeredSlides'] );
3275 + unset( $dataset['centeredSlidesSettings'] );
3276 + }
3129 3277 }
3130 3278 }
3131 3279
3132 - // centeredSlides.
3133 - $dataset['centeredSlides'] = $carousel_settings['centeredSlides'] ?? false;
3134 - if ($dataset['centeredSlides'] && $effect === 'slide' && ($carousel_settings['centeredSlidesSettings']['enable'] ?? '')) {
3135 - $dataset['centeredSlidesSettings'] = $carousel_settings['centeredSlidesSettings'];
3136 - }
3137 -
3138 3280 // Pagination.
3139 3281 $pagination = $carousel_settings['pagination'] ?? [];
3140 3282 $dataset['pagination'] = $pagination['enable'] ?? false;
3141 3283 if ( $dataset['pagination'] ) {
@@ -3145,8 +3287,20 @@
3145 3287 // Navigation.
3146 3288 $navigation = $carousel_settings['navigation'] ?? [];
3147 3289 $dataset['navigation'] = $navigation['enable'] ?? false;
3148 3290 if ( $dataset['navigation'] ) {
3291 + $next_icon = trim($navigation['nextIcon']['value'] ?? '');
3292 + $prev_icon = trim($navigation['prevIcon']['value'] ?? '');
3293 + if ( $next_icon || $prev_icon ) {
3294 + $svg_sanitizer = $this->the_plugin_instance->get_component( IconLibrary::class );
3295 + if ($svg_sanitizer) {
3296 + $next_icon = $next_icon ? $svg_sanitizer->sanitize_svg( $next_icon ) : '';
3297 + $prev_icon = $prev_icon ? $svg_sanitizer->sanitize_svg( $prev_icon ) : '';
3298 +
3299 + $navigation['nextIcon']['value'] = $next_icon;
3300 + $navigation['prevIcon']['value'] = $prev_icon;
3301 + }
3302 + }
3149 3303 $dataset['navigationSettings'] = $navigation;
3150 3304 }
3151 3305
3152 3306 // Scrollbar.
@@ -3173,9 +3327,9 @@
3173 3327 if ( $exclude_li_role ) {
3174 3328 $dataset['a11y'] = ['slideRole' => '', 'slideLabelMessage' => ''];
3175 3329 }
3176 3330
3177 - return wp_json_encode( $dataset );
3331 + return wp_json_encode( apply_filters( 'cbb_get_carousel_settings', $dataset, $parsed_block, $block_instance ) );
3178 3332 // phpcs:enable
3179 3333 }
3180 3334
3181 3335 /**
@@ -3181,9 +3335,9 @@
3181 3335 /**
3182 3336 * Refine the slides per view
3183 3337 *
3184 3338 * @param mixed $raw_value
3185 - * @return void
3339 + * @return string|float 'auto' || number
3186 3340 */
3187 3341 private function carousel_refine_slides_per_view( $raw_value ) {
3188 3342 $value = $raw_value;
3189 3343 if ( is_array( $raw_value ) ) {
@@ -3521,9 +3675,9 @@
3521 3675 // Carousel settings.
3522 3676 $carousel_settings = $block['attrs']['boldblocks']['carousel'] ?? [];
3523 3677
3524 3678 // Dataset attribute.
3525 - $carousel_dataset = $this->build_carousel_settings( $carousel_settings );
3679 + $carousel_dataset = $this->build_carousel_settings( $carousel_settings, false, $block, $block_instance );
3526 3680 if ( $carousel_dataset ) {
3527 3681 $block_content = $this->add_data_to_block( $block_content, 'data-carousel-settings', esc_attr( $carousel_dataset ) );
3528 3682 }
3529 3683
@@ -3559,9 +3713,9 @@
3559 3713 return apply_filters( 'cbb_carousel_preloader', '<div class="cbb-loader"></div>', $block, $block_instance );
3560 3714 }
3561 3715
3562 3716 /**
3563 - * Migrate cbb class for old CBB blocks.
3717 + * Manage css class: migrate old class and adding custom css class.
3564 3718 *
3565 3719 * @param string $block_content
3566 3720 * @param array $block
3567 3721 * @param WP_Block $block_instance
@@ -3566,28 +3720,51 @@
3566 3720 * @param array $block
3567 3721 * @param WP_Block $block_instance
3568 3722 * @return string
3569 3723 */
3570 - public function migrate_cbb_class( $block_content, $block, $block_instance ) {
3724 + public function manage_cbb_class( $block_content, $block, $block_instance ) {
3571 3725 // Ignore admin side or empty content.
3572 3726 if ( is_admin() || ! $block_content ) {
3573 3727 return $block_content;
3574 3728 }
3575 3729
3576 - // There is no need to migrate.
3577 - $migrate_cbb_class = $block_instance->block_type->supports['migrateClass'] ?? '';
3578 - if ( ! $migrate_cbb_class ) {
3730 + // Bail if it is not a CBB block.
3731 + if ( empty( $block_instance->block_type->supports['cbb'] ?? '' ) ) {
3579 3732 return $block_content;
3580 3733 }
3581 3734
3582 - // Replace the class.
3583 - $block_reader = new \WP_HTML_Tag_Processor( $block_content );
3584 - if ( $block_reader->next_tag( [ 'class_name' => $migrate_cbb_class ] ) ) {
3585 - $new_class = str_ends_with( $migrate_cbb_class, 'custom' ) ? 'cbb-block' : 'cbb-block-parent';
3586 - $block_reader->set_attribute( 'class', str_replace( $migrate_cbb_class, $new_class, $block_reader->get_attribute( 'class' ) ) );
3735 + // Get custom classes.
3736 + $css_classes = trim( $block_instance->block_type->supports['CSSClasses'] ?? '' );
3587 3737
3738 + // Get migrate class.
3739 + $migrate_class = trim( $block_instance->block_type->supports['migrateClass'] ?? '' );
3740 +
3741 + // Bail if we don't need to process.
3742 + if ( ! $css_classes && ! $migrate_class ) {
3743 + return $block_content;
3744 + }
3745 +
3746 + // Initialize the HTML Tag Processor.
3747 + $p = new \WP_HTML_Tag_Processor( $block_content );
3748 +
3749 + // Target only the very first outer wrapping element.
3750 + if ( $p->next_tag() ) {
3751 + if ( $migrate_class ) {
3752 + $p->remove_class( $migrate_class );
3753 + $p->add_class( str_ends_with( $migrate_class, 'custom' ) ? 'cbb-block' : 'cbb-block-parent' );
3754 + }
3755 +
3756 + if ( $css_classes ) {
3757 + // Explode by space in case multiple custom classes are supplied.
3758 + foreach ( explode( ' ', $css_classes ) as $single_class ) {
3759 + if ( ! empty( $single_class ) ) {
3760 + $p->add_class( $single_class );
3761 + }
3762 + }
3763 + }
3764 +
3588 3765 // Render the updated HTML.
3589 - return $block_reader->get_updated_html();
3766 + return $p->get_updated_html();
3590 3767 }
3591 3768
3592 3769 return $block_content;
3593 3770 }
@@ -3592,8 +3769,44 @@
3592 3769 return $block_content;
3593 3770 }
3594 3771
3595 3772 /**
3773 + * Render steps block data
3774 + *
3775 + * @param array $parsed_block
3776 + * @param array $block
3777 + * @param WP_Block $parent_block
3778 + * @return array
3779 + */
3780 + public function render_steps_block_data( $parsed_block, $block, $parent_block ) {
3781 + if ( ! $parent_block || empty( $parent_block->attributes['boldblocks']['steps']['enableSteps'] ) ) {
3782 + return $parsed_block;
3783 + }
3784 +
3785 + // Mark it as a child of steps.
3786 + $parsed_block['attrs']['boldblocks']['childStep'] = true;
3787 +
3788 + return $parsed_block;
3789 + }
3790 +
3791 + /**
3792 + * Render aria attributes for steps blocks
3793 + *
3794 + * @param string $block_content
3795 + * @param array $block
3796 + * @return string
3797 + */
3798 + public function render_steps_attributes( $block_content, $block ) {
3799 + if ( ! empty( $block['attrs']['boldblocks']['steps']['enableSteps'] ) ) {
3800 + $block_content = $this->add_data_to_block( $block_content, 'role', 'list' );
3801 + } elseif ( ! empty( $block['attrs']['boldblocks']['childStep'] ) ) {
3802 + $block_content = $this->add_data_to_block( $block_content, 'role', 'listitem' );
3803 + }
3804 +
3805 + return $block_content;
3806 + }
3807 +
3808 + /**
3596 3809 * Support block style for non-cbb blocks
3597 3810 *
3598 3811 * @param string $is_supported
3599 3812 * @param array $block
@@ -3804,8 +4017,9 @@
3804 4017 /**
3805 4018 * Add data attribute to block wrapper
3806 4019 *
3807 4020 * @param string $block_content
4021 + * @param string $name
3808 4022 * @param string $value
3809 4023 * @return string
3810 4024 */
3811 4025 public function add_data_to_block( $block_content, $name, $value ) {
@@ -3837,8 +4051,46 @@
3837 4051 return $block_content;
3838 4052 }
3839 4053
3840 4054 /**
4055 + * Get inner html of a tag
4056 + *
4057 + * @param string $content
4058 + * @param string $tag_name
4059 + * @return string
4060 + */
4061 + public function get_element_inner_html( $content, $tag_name ) {
4062 + $processor = new class( $content ) extends \WP_HTML_Tag_Processor {
4063 + public function get_inner_html( $tag_name ) {
4064 + $this->set_bookmark( 'open' );
4065 + $opener = $this->bookmarks['open'];
4066 +
4067 + while ( $this->next_token() ) {
4068 + if ( $this->get_tag() === $tag_name && $this->is_tag_closer() ) {
4069 +
4070 + $this->set_bookmark( 'close' );
4071 + $closer = $this->bookmarks['close'];
4072 +
4073 + return substr(
4074 + $this->html,
4075 + $opener->start + $opener->length,
4076 + $closer->start - $opener->start - $opener->length
4077 + );
4078 + }
4079 + }
4080 +
4081 + return '';
4082 + }
4083 + };
4084 +
4085 + if ( ! $processor->next_tag( $tag_name ) ) {
4086 + return '';
4087 + }
4088 +
4089 + return $processor->get_inner_html( $tag_name );
4090 + }
4091 +
4092 + /**
3841 4093 * Detect a value is valid
3842 4094 *
3843 4095 * @param mixed $value
3844 4096 * @return boolean
@@ -3906,8 +4158,66 @@
3906 4158 }
3907 4159 }
3908 4160
3909 4161 return $value;
4162 + }
4163 +
4164 + /**
4165 + * Sanitize post data
4166 + *
4167 + * @param array $data
4168 + * @return array
4169 + */
4170 + public function sanitize_post_data( $data ) {
4171 + if ( empty( $data['post_content'] ) ) {
4172 + return $data;
4173 + }
4174 +
4175 + if ( ! $this->user_can_edit_css() ) {
4176 + $blocks = parse_blocks( wp_unslash( $data['post_content'] ) );
4177 +
4178 + // Strip custom css from blocks.
4179 + $modified = false;
4180 + $blocks = $this->remove_custom_css_from_blocks( $blocks, $modified );
4181 +
4182 + if ( $modified ) {
4183 + $data['post_content'] = wp_slash( serialize_blocks( $blocks ) );
4184 + }
4185 + }
4186 +
4187 + return $data;
4188 + }
4189 +
4190 + /**
4191 + * Remove custom css if any
4192 + *
4193 + * @param array $blocks
4194 + * @param boolean $modified
4195 + * @return array
4196 + */
4197 + private function remove_custom_css_from_blocks( $blocks, &$modified = false ) {
4198 + foreach ( $blocks as &$block ) {
4199 + if ( ! empty( $block['attrs']['boldblocks']['customCSS']['value'] ) ) {
4200 + $block['attrs']['boldblocks']['customCSS']['value'] = '';
4201 + $modified = true;
4202 + }
4203 +
4204 + // Recursive for inner blocks.
4205 + if ( ! empty( $block['innerBlocks'] ) ) {
4206 + $block['innerBlocks'] = $this->remove_custom_css_from_blocks( $block['innerBlocks'], $modified );
4207 + }
4208 + }
4209 +
4210 + return $blocks;
4211 + }
4212 +
4213 + /**
4214 + * If the current user can edit css
4215 + *
4216 + * @return boolean
4217 + */
4218 + public function user_can_edit_css() {
4219 + return apply_filters( 'cbb_user_can_edit_css', current_user_can( 'manage_options' ) );
3910 4220 }
3911 4221
3912 4222 /**
3913 4223 * Refine custom JS and CSS value