* @copyright Copyright (c) 2022, Phi Phan */ namespace BoldBlocks; // Exit if accessed directly. defined( 'ABSPATH' ) || exit; if ( ! class_exists( CustomStyle::class ) ) : /** * The controller class for style. */ class CustomStyle extends CoreComponent { /** * The style handle for feature styles * * @var array */ private $feature_style_handle = 'cbb-dynamic-style'; /** * Store the context of styles * * @var array */ private $style_contexts = [ 'loops' => [], 'loop' => '', 'post' => 0, 'counter' => 0, 'content' => false, 'content_counter' => 0, ]; /** * Store the ID of query loop with carousel or grid layout * * @var array */ private $query_ids = []; /** * The cached styles * * @var array */ private $styles = []; /** * The refined breakpoints * * @var array */ private $breakpoints = []; /** * The list of non-cbb blocks that support dynamic style * * @var array */ public $non_cbb_blocks = [ 'core/template-part' ]; /** * Run main hooks * * @return void */ public function run() { // Register setting fields. add_action( 'init', [ $this, 'register_setting_fields' ] ); // Register style handle. add_action( 'init', [ $this, 'register_feature_style' ] ); // Render block style. add_filter( 'render_block', [ $this, 'render_block_style' ], 10, 3 ); // Render link to post first. add_filter( 'render_block', [ $this, 'build_block_link_to_post' ], 20, 3 ); // Build dynamic block overlay. add_filter( 'render_block', [ $this, 'build_block_overlay' ], 20, 3 ); // Build dynamic block background. add_filter( 'render_block', [ $this, 'build_block_background' ], 30, 3 ); // Build animations. add_filter( 'render_block', [ $this, 'build_block_animations' ], 30, 3 ); // Render accordions. add_filter( 'render_block_data', [ $this, 'render_accordion_block_data' ] ); // Render accordion item blocks. add_filter( 'render_block', [ $this, 'render_accordion_item_block' ], 10, 3 ); // Render grid style for the query loop block. add_filter( 'render_block_core/query', [ $this, 'render_query_loop_grid_style' ], 10, 3 ); // Render carousel settings for the query loop block. add_filter( 'render_block_core/query', [ $this, 'render_query_loop_carousel_layout' ], 10, 3 ); // Enqueue block styles. add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_responsive_styles' ] ); // Enqueue breakpoints. add_action( 'init', [ $this, 'enqueue_reponsive_breakpoints' ] ); // Update loop id. add_filter( 'render_block_context', [ $this, 'update_loop_id' ], 10, 2 ); // Reset loop id. add_filter( 'render_block', [ $this, 'reset_loop_id' ], 10, 2 ); // Render preload style for carousels. add_filter( 'cbb_get_block_style', [ $this, 'get_carousel_preload_style' ], 10, 2 ); // Support dynamic style for none-cbb blocks. add_filter( 'cbb_support_block_style', [ $this, 'support_block_style' ], 10, 2 ); // Set a block layout for non-cbb blocks. add_filter( 'cbb_get_block_layout', [ $this, 'get_block_layout' ], 10, 2 ); // Render sticky data for the core/template-part block. add_filter( 'render_block_core/template-part', [ $this, 'render_template_part_sticky' ], 10, 3 ); // Render settings for carousels. add_filter( 'render_block', [ $this, 'render_carousel_settings' ], 30, 3 ); // Migrate CBB class for old blocks. add_filter( 'render_block', [ $this, 'migrate_cbb_class' ], 30, 3 ); } /** * Register custom setting fields * * @return void */ public function register_setting_fields() { // phpcs:ignore PluginCheck.CodeAnalysis.SettingSanitization.register_settingDynamic register_setting( 'cbb', 'cbb_breakpoints', [ 'type' => 'array', 'show_in_rest' => [ 'name' => 'CBBBreakpoints', 'schema' => [ 'items' => [ 'type' => 'object', 'properties' => [ 'breakpoint' => [ 'type' => 'number', ], 'prefix' => [ 'type' => 'string', ], ], 'additionalProperties' => [ 'type' => 'string', ], ], ], ], 'default' => [ [ 'breakpoint' => 576, 'prefix' => 'sm', ], [ 'breakpoint' => 768, 'prefix' => 'md', ], [ 'breakpoint' => 1024, 'prefix' => 'lg', ], ], ] ); } /** * Enqueue responsive breakpoints * * @return void */ public function enqueue_reponsive_breakpoints() { // Custom blocks handle. $custom_blocks_handler = $this->the_plugin_instance->get_component( CustomBlocks::class ); // Get breakpoint setting. $breakpoints = $this->get_breakpoints(); // Get breakpoint scripts. $breakpoint_script = 'var CBBBreakpoints=' . wp_json_encode( $breakpoints ); // Load JS breakpoints. wp_add_inline_script( $custom_blocks_handler->custom_blocks_handle, $breakpoint_script, 'before' ); wp_add_inline_script( $custom_blocks_handler->carousel_blocks_frontend_handle, $breakpoint_script, 'before' ); } /** * Register a handle for enqueue block styles. * * @return void */ public function register_feature_style() { // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion wp_register_style( $this->feature_style_handle, '' ); } /** * Enqueue all feature styles * * @return void */ public function enqueue_responsive_styles() { if ( wp_is_block_theme() ) { wp_enqueue_style( $this->feature_style_handle ); } wp_add_inline_style( $this->feature_style_handle, $this->get_responsive_styles() ); } /** * Build responsive styles * * @return string */ private function get_responsive_styles() { $style = ''; $breakpoints = $this->get_breakpoints(); $md_breakpoint = absint( $breakpoints['md']['breakpoint'] ?? 768 ); $md_breakpoint_max = $md_breakpoint - 1; $lg_breakpoint = absint( $breakpoints['lg']['breakpoint'] ?? 1024 ); $lg_breakpoint_max = $lg_breakpoint - 1; $md_start = "@media(min-width:{$md_breakpoint}px){"; $lg_start = "@media(min-width:{$lg_breakpoint}px){"; $end = '}'; // Padding. $padding_style = '.sm-cbb-padding-top{padding-top:var(--cbb--padding-top) !important;}.sm-cbb-padding-right{padding-right:var(--cbb--padding-right) !important;}.sm-cbb-padding-bottom{padding-bottom:var(--cbb--padding-bottom) !important;}.sm-cbb-padding-left{padding-left:var(--cbb--padding-left) !important;}'; $padding_style .= "{$md_start}.md-cbb-padding-top{padding-top:var(--cbb--padding-top) !important;}.md-cbb-padding-right{padding-right:var(--cbb--padding-right) !important;}.md-cbb-padding-bottom{padding-bottom:var(--cbb--padding-bottom) !important;}.md-cbb-padding-left{padding-left:var(--cbb--padding-left) !important;}{$end}"; $padding_style .= "{$lg_start}.lg-cbb-padding-top{padding-top:var(--cbb--padding-top) !important;}.lg-cbb-padding-right{padding-right:var(--cbb--padding-right) !important;}.lg-cbb-padding-bottom{padding-bottom:var(--cbb--padding-bottom) !important;}.lg-cbb-padding-left{padding-left:var(--cbb--padding-left) !important;}{$end}"; $style .= $padding_style; // Margin. $margin_style = '.sm-cbb-margin-top{margin-top:var(--cbb--margin-top) !important;}.sm-cbb-margin-right{margin-right:var(--cbb--margin-right) !important;}.sm-cbb-margin-bottom{margin-bottom:var(--cbb--margin-bottom) !important;}.sm-cbb-margin-left{margin-left:var(--cbb--margin-left) !important;}'; $margin_style .= "{$md_start}.md-cbb-margin-top{margin-top:var(--cbb--margin-top) !important;}.md-cbb-margin-right{margin-right:var(--cbb--margin-right) !important;}.md-cbb-margin-bottom{margin-bottom:var(--cbb--margin-bottom) !important;}.md-cbb-margin-left{margin-left:var(--cbb--margin-left) !important;}{$end}"; $margin_style .= "{$lg_start}.lg-cbb-margin-top{margin-top:var(--cbb--margin-top) !important;}.lg-cbb-margin-right{margin-right:var(--cbb--margin-right) !important;}.lg-cbb-margin-bottom{margin-bottom:var(--cbb--margin-bottom) !important;}.lg-cbb-margin-left{margin-left:var(--cbb--margin-left) !important;}{$end}"; $style .= $margin_style; // Block gap. $block_gap_style = '.sm-cbb-block-gap > *{margin-block-start:0;margin-block-end:0;}.sm-cbb-block-gap > * + *{margin-block-start:var(--cbb--block-gap) !important;margin-block-end:0;}'; $block_gap_style .= "{$md_start}.md-cbb-block-gap > *{margin-block-start:0;margin-block-end:0;}.md-cbb-block-gap > * + *{margin-block-start:var(--cbb--block-gap) !important;margin-block-end:0;}{$end}"; $block_gap_style .= "{$lg_start}.lg-cbb-block-gap > *{margin-block-start:0;margin-block-end:0;}.lg-cbb-block-gap > * + *{margin-block-start:var(--cbb--block-gap) !important;margin-block-end:0;}{$end}"; $style .= $block_gap_style; // Border. $border_style = '.sm-cbb-border-top{border-top:var(--cbb--border-top) !important;}.sm-cbb-border-right{border-right:var(--cbb--border-right) !important;}.sm-cbb-border-bottom{border-bottom:var(--cbb--border-bottom) !important;}.sm-cbb-border-left{border-left:var(--cbb--border-left) !important;}'; $border_style .= "{$md_start}.md-cbb-border-top{border-top:var(--cbb--border-top) !important;}.md-cbb-border-right{border-right:var(--cbb--border-right) !important;}.md-cbb-border-bottom{border-bottom:var(--cbb--border-bottom) !important;}.md-cbb-border-left{border-left:var(--cbb--border-left) !important;}{$end}"; $border_style .= "{$lg_start}.lg-cbb-border-top{border-top:var(--cbb--border-top) !important;}.lg-cbb-border-right{border-right:var(--cbb--border-right) !important;}.lg-cbb-border-bottom{border-bottom:var(--cbb--border-bottom) !important;}.lg-cbb-border-left{border-left:var(--cbb--border-left) !important;}{$end}"; $style .= $border_style; // Border radius. $radius_style = '.sm-cbb-border-radius{overflow:hidden;border-radius: var(--cbb--border-radius) !important;}'; $radius_style .= "{$md_start}.md-cbb-border-radius{overflow:hidden;border-radius: var(--cbb--border-radius) !important;}{$end}"; $radius_style .= "{$lg_start}.lg-cbb-border-radius{overflow:hidden;border-radius: var(--cbb--border-radius) !important;}{$end}"; $style .= $radius_style; // Width. $width_style = '.sm-cbb-width{width:var(--cbb--width) !important;}'; $width_style .= "{$md_start}.md-cbb-width{width:var(--cbb--width) !important;}{$end}"; $width_style .= "{$lg_start}.lg-cbb-width{width:var(--cbb--width) !important;}{$end}"; $style .= $width_style; // Height. $height_style = '.sm-cbb-height{height:var(--cbb--height) !important;}'; $height_style .= "{$md_start}.md-cbb-height{height:var(--cbb--height) !important;}{$end}"; $height_style .= "{$lg_start}.lg-cbb-height{height:var(--cbb--height) !important;}{$end}"; $style .= $height_style; // Aspect ratio. $aspect_ratio_style = '.sm-cbb-aspect-ratio{aspect-ratio:var(--cbb--aspect-ratio);}'; $aspect_ratio_style .= "{$md_start}.md-cbb-aspect-ratio{aspect-ratio:var(--cbb--aspect-ratio);}{$end}"; $aspect_ratio_style .= "{$lg_start}.lg-cbb-aspect-ratio{aspect-ratio:var(--cbb--aspect-ratio);}{$end}"; $style .= $aspect_ratio_style; // Text alignment. $text_align_style = '.sm-cbb-text-align{text-align:var(--cbb--text-align);}'; $text_align_style .= "{$md_start}.md-cbb-text-align{text-align:var(--cbb--text-align);}{$end}"; $text_align_style .= "{$lg_start}.lg-cbb-text-align{text-align:var(--cbb--text-align);}{$end}"; $style .= $text_align_style; // Vertical alignment. $v_align_style = '.sm-cbb-v-align.cbb-layout-grid{display:grid;align-content:var(--cbb--v-align);}.sm-cbb-v-align.cbb-layout-grid>*{width:100%;}.sm-cbb-v-align.cbb-align-items{align-items:var(--cbb--v-align);}.sm-cbb-v-align.cbb-align-self{align-self:var(--cbb--v-align);}'; $v_align_style .= "{$md_start}.md-cbb-v-align.cbb-layout-grid{display:grid;align-content:var(--cbb--v-align);}.md-cbb-v-align.cbb-layout-grid>*{width:100%;}.md-cbb-v-align.cbb-align-items{align-items:var(--cbb--v-align);}.md-cbb-v-align.cbb-align-self{align-self:var(--cbb--v-align);}{$end}"; $v_align_style .= "{$lg_start}.lg-cbb-v-align.cbb-layout-grid{display:grid;align-content:var(--cbb--v-align);}.lg-cbb-v-align.cbb-layout-grid>*{width:100%;}.lg-cbb-v-align.cbb-align-items{align-items:var(--cbb--v-align);}.lg-cbb-v-align.cbb-align-self{align-self:var(--cbb--v-align);}{$end}"; $style .= $v_align_style; // Justify alignment. $h_align_style = '.sm-cbb-h-align.cbb-layout-grid{display:grid;justify-content:var(--cbb--h-align);}.sm-cbb-h-align.cbb-layout-grid>*{width:auto;}.sm-cbb-h-align.cbb-justify-items{justify-items:var(--cbb--h-align);}.sm-cbb-h-align.cbb-justify-self{justify-self:var(--cbb--h-align);}'; $h_align_style .= "{$md_start}.md-cbb-h-align.cbb-layout-grid{display:grid;justify-content:var(--cbb--h-align);}.md-cbb-h-align.cbb-layout-grid>*{width:auto;}.md-cbb-h-align.cbb-justify-items{justify-items:var(--cbb--h-align);}.md-cbb-h-align.cbb-justify-self{justify-self:var(--cbb--h-align);}{$end}"; $h_align_style .= "{$lg_start}.lg-cbb-h-align.cbb-layout-grid{display:grid;justify-content:var(--cbb--h-align);}.lg-cbb-h-align.cbb-layout-grid>*{width:auto;}.lg-cbb-h-align.cbb-justify-items{justify-items:var(--cbb--h-align);}.lg-cbb-h-align.cbb-justify-self{justify-self:var(--cbb--h-align);}{$end}"; $style .= $h_align_style; // Transform. $transform_style = '.sm-cbb-transform{transform:var(--cbb--transform);transform-origin:var(--cbb--transform-origin)}'; $transform_style .= "{$md_start}.md-cbb-transform{transform:var(--cbb--transform);transform-origin:var(--cbb--transform-origin)}{$end}"; $transform_style .= "{$lg_start}.lg-cbb-transform{transform:var(--cbb--transform);transform-origin:var(--cbb--transform-origin)}{$end}"; $style .= $transform_style; // Visibility. $visibility_style = "@media(max-width:{$md_breakpoint_max}px){.cbb-hidden-sm{display:none !important;}}"; $visibility_style .= "@media(min-width:{$md_breakpoint}px) and (max-width:{$lg_breakpoint_max}px){.cbb-hidden-md{display:none !important;}}"; $visibility_style .= "@media(min-width:{$lg_breakpoint}px){.cbb-hidden-lg{display:none !important;}}"; $style .= $visibility_style; // Grid: Columns, rows, auto-rows, & gap. $grid_style = '.sm-cbb-grid-columns > *,.sm-cbb-grid-columns > * + *{margin:0}.sm-cbb-grid-columns{grid-template-columns:var(--cbb--grid-columns);}.sm-cbb-grid-rows{grid-template-rows:var(--cbb--grid-rows);}.sm-cbb-grid-auto-rows{grid-auto-rows:var(--cbb--grid-auto-rows);}.sm-cbb-grid-gap-column{column-gap:var(--cbb--grid-gap-column);}.sm-cbb-grid-gap-row{row-gap:var(--cbb--grid-gap-row);}'; $grid_style .= "{$md_start}.md-cbb-grid-columns > * {margin:0}.md-cbb-grid-columns{grid-template-columns:var(--cbb--grid-columns);}.md-cbb-grid-rows{grid-template-rows:var(--cbb--grid-rows);}.md-cbb-grid-auto-rows{grid-auto-rows:var(--cbb--grid-auto-rows);}.md-cbb-grid-gap-column{column-gap:var(--cbb--grid-gap-column);}.md-cbb-grid-gap-row{row-gap:var(--cbb--grid-gap-row);}{$end}"; $grid_style .= "{$lg_start}.lg-cbb-grid-columns > * {margin:0}.lg-cbb-grid-columns{grid-template-columns:var(--cbb--grid-columns);}.lg-cbb-grid-rows{grid-template-rows:var(--cbb--grid-rows);}.lg-cbb-grid-auto-rows{grid-auto-rows:var(--cbb--grid-auto-rows);}.lg-cbb-grid-gap-column{column-gap:var(--cbb--grid-gap-column);}.lg-cbb-grid-gap-row{row-gap:var(--cbb--grid-gap-row);}{$end}"; $style .= $grid_style; // Grid item: columnSpan & rowSpan. $grid_item_style = '.sm-cbb-grid-item-column{grid-column:var(--cbb--grid-item-column);}.sm-cbb-grid-item-row{grid-row:var(--cbb--grid-item-row);}.sm-cbb-grid-item-order{order:var(--cbb--grid-item-order);}'; $grid_item_style .= "{$md_start}.md-cbb-grid-item-column{grid-column:var(--cbb--grid-item-column);}.md-cbb-grid-item-row{grid-row:var(--cbb--grid-item-row);}.md-cbb-grid-item-order{order:var(--cbb--grid-item-order);}{$end}"; $grid_item_style .= "{$lg_start}.lg-cbb-grid-item-column{grid-column:var(--cbb--grid-item-column);}.lg-cbb-grid-item-row{grid-row:var(--cbb--grid-item-row);}.lg-cbb-grid-item-order{order:var(--cbb--grid-item-order);}{$end}"; $style .= $grid_item_style; // Accordion gap. $accordion_gap_style = '.sm-cbb-accordion-gap{display:flex;flex-direction:column;gap:var(--cbb--accordion-gap);}.sm-cbb-a-has-border > .is-accordion-item{border-top:var(--cbb--ab-top);}.sm-cbb-a-no-border > .is-accordion-item{border-top:0;}'; $accordion_gap_style .= "{$md_start}.md-cbb-accordion-gap{display:flex;flex-direction:column;gap:var(--cbb--accordion-gap);}.md-cbb-a-has-border > .is-accordion-item{border-top:var(--cbb--ab-top);}.md-cbb-a-no-border > .is-accordion-item{border-top:0;}{$end}"; $accordion_gap_style .= "{$lg_start}.lg-cbb-accordion-gap{display:flex;flex-direction:column;gap:var(--cbb--accordion-gap);}.lg-cbb-a-has-border > .is-accordion-item{border-top:var(--cbb--ab-top);}.lg-cbb-a-no-border > .is-accordion-item{border-top:0;}{$end}"; $style .= $accordion_gap_style; // Accordion padding. // We don't need padding style, because it has a default value. // Sticky offset. $sticky_offset_style = '.is-stick-to-top.sm-cbb-sticky-offset{top: var(--cbb--sticky-offset);}.is-stick-to-bottom.sm-cbb-sticky-offset{bottom: var(--cbb--sticky-offset);}'; $sticky_offset_style .= "{$md_start}.is-stick-to-top.md-cbb-sticky-offset{top: var(--cbb--sticky-offset);}.is-stick-to-bottom.md-cbb-sticky-offset{bottom: var(--cbb--sticky-offset);}{$end}"; $sticky_offset_style .= "{$lg_start}.is-stick-to-top.lg-cbb-sticky-offset{top: var(--cbb--sticky-offset);}.is-stick-to-bottom.lg-cbb-sticky-offset{bottom: var(--cbb--sticky-offset);}{$end}"; $style .= $sticky_offset_style; // Offcanvas. $offcanvas_style = "{$md_start}.is-offcanvas.placement-start,.is-offcanvas.placement-end{width:var(--bb--modal-width--md,25rem);}.is-offcanvas.placement-top,.is-offcanvas.placement-bottom{height:var(--bb--modal-height--md,30vh);}{$end}"; $offcanvas_style .= "{$lg_start}.is-offcanvas.placement-start,.is-offcanvas.placement-end{width:var(--bb--modal-width--lg,25rem);}.is-offcanvas.placement-top,.is-offcanvas.placement-bottom{height:var(--bb--modal-height--lg,30vh);}{$end}"; $style .= $offcanvas_style; // Popover. $popover_style = "{$md_start}.is-popover{width:var(--bb--modal-width--md,auto);height:var(--bb--modal-height--md,auto);}{$end}"; $popover_style .= "{$lg_start}.is-popover{width:var(--bb--modal-width--lg,auto);height:var(--bb--modal-height--lg,auto);}{$end}"; $style .= $popover_style; // Modal. $modal_style = "{$md_start}.is-modal > .bb-modal-dialog{width:var(--bb--modal-width--md,32rem);}.is-modal > .bb-modal-dialog[style*=\"--bb--modal-height--md:\"]{height:var(--bb--modal-height--md);}.modal--custom-position{align-items:var(--bb--modal-v-align--md);justify-content:var(--bb--modal-h-align--md);}{$end}"; $modal_style .= "{$lg_start}.is-modal > .bb-modal-dialog{width:var(--bb--modal-width--md,50rem);}.is-modal > .bb-modal-dialog[style*=\"--bb--modal-height--lg:\"]{height:var(--bb--modal-height--lg);}.modal--custom-position{align-items:var(--bb--modal-v-align--lg);justify-content:var(--bb--modal-h-align--lg);}{$end}"; $style .= $modal_style; // Mobile background. $background_style = '.cbb-mobile-image > .bb\:block-background--img{display:none !important;}.cbb-mobile-image > .is-mobile-image {display:block !important;}'; $background_style .= "@media(min-width:{$md_breakpoint}px){.cbb-mobile-image > .bb\:block-background--img{display:block !important;}.cbb-mobile-image > .is-mobile-image {display:none !important;}}"; $background_style .= "@media(max-width:{$md_breakpoint_max}px){.cbb-mobile-background{background-image: var(--cbb-mobile-background) !important;}}"; $style .= $background_style; return $style; } /** * Render style for all supported blocks * * @param string $block_content * @param array $block * @param WP_Block $block_instance * @return string */ public function render_block_style( $block_content, $block, $block_instance ) { // Ignore admin side. if ( is_admin() ) { return $block_content; } // Bail if the block has no style. if ( ! $this->has_style( $block, $block_instance ) ) { return $block_content; } // Buil selector. $selector = $this->generate_selector( $block['blockName'], $block_instance ); // Get custom style. $is_in_cache = isset( $this->styles[ $selector ] ); if ( $is_in_cache ) { $block_styles = $this->styles[ $selector ]; } else { $block_styles = $this->get_block_style( $block, $selector, $block_instance ); // Add to the cache. $this->styles[ $selector ] = $block_styles; } if ( empty( $block_styles['style'] ?? '' ) ) { if ( isset( $block_styles['classes'] ) && count( $block_styles['classes'] ) > 1 ) { // There is no style, but we have class-features like visibility. $block_content = $this->add_class_to_block( $block_content, implode( ' ', $block_styles['classes'] ) ); } return $block_content; } if ( ! wp_is_block_theme() ) { // Enqueue style. wp_enqueue_style( $this->feature_style_handle ); } if ( ! $is_in_cache ) { wp_add_inline_style( $this->feature_style_handle, $block_styles['style'] ); } // Add selector to block wrapper element. $block_content = $this->add_class_to_block( $block_content, implode( ' ', $block_styles['classes'] ) ); return $block_content; } /** * Get block custom style * * @param array $block * @param string $selector * @param WP_Block $block_instance * @return string */ private function get_block_style( $block, $selector, $block_instance ) { $style = ''; $class_selector = '.' . $selector; $classes = [ $selector ]; $style_array = []; $responsive_style_array = []; // Get responsive settings. $breakpoints = $this->get_breakpoints(); // Get the settings. $settings = $block['attrs']['boldblocks']; // Features. $features = [ 'padding' => [ 'func_build_responsive_style' => [ $this, 'build_padding_style' ], 'group' => 'spacing', ], 'margin' => [ 'func_build_responsive_style' => [ $this, 'build_margin_style' ], 'group' => 'spacing', ], 'blockGap' => [ 'func_build_responsive_style' => [ $this, 'build_block_gap_style' ], 'group' => 'spacing', ], 'border' => [ 'func_build_responsive_style' => [ $this, 'build_border_style' ] ], 'borderRadius' => [ 'func_build_responsive_style' => [ $this, 'build_border_radius_style' ] ], 'width' => [ 'func_build_responsive_style' => [ $this, 'build_width_style' ] ], 'height' => [ 'func_build_responsive_style' => [ $this, 'build_height_style' ] ], 'aspectRatio' => [ 'func_build_responsive_style' => [ $this, 'build_aspect_ratio_style' ] ], 'textAlignment' => [ 'func_build_responsive_style' => [ $this, 'build_text_align_style' ] ], 'verticalAlignment' => [ 'func_build_responsive_style' => [ $this, 'build_vertical_align_style' ], 'func_build_dependent_style' => [ $this, 'build_vertical_align_dependent_style' ], ], 'justifyAlignment' => [ 'func_build_responsive_style' => [ $this, 'build_justify_align_style' ], 'func_build_dependent_style' => [ $this, 'build_justify_align_dependent_style' ], ], 'transform' => [ 'func_build_responsive_style' => [ $this, 'build_transform_style' ], 'func_build_dependent_style' => [ $this, 'build_transform_dependent_style' ], ], 'hidden' => [ 'func_build_style' => [ $this, 'build_hidden_style' ], 'group' => 'visibility', ], 'columns' => [ 'func_build_responsive_style' => [ $this, 'build_columns_style' ], 'group' => 'grid', 'layout_type' => 'grid', ], 'rows' => [ 'func_build_responsive_style' => [ $this, 'build_rows_style' ], 'group' => 'grid', 'layout_type' => 'grid', ], 'autoRows' => [ 'func_build_responsive_style' => [ $this, 'build_auto_rows_style' ], 'group' => 'grid', 'layout_type' => 'grid', ], 'gap' => [ 'func_build_responsive_style' => [ $this, 'build_gap_style' ], 'group' => 'grid', 'layout_type' => 'grid', ], 'columnSpan' => [ 'func_build_responsive_style' => [ $this, 'build_column_span_style' ], 'group' => 'gridItem', 'layout_type' => 'gridItem', ], 'rowSpan' => [ 'func_build_responsive_style' => [ $this, 'build_row_span_style' ], 'group' => 'gridItem', 'layout_type' => 'gridItem', ], 'accordionGap' => [ 'func_build_responsive_style' => [ $this, 'build_accordion_gap_style' ], 'func_build_dependent_style' => [ $this, 'build_accordion_gap_dependent_style' ], 'group' => 'accordion', 'setting_name' => 'gap', 'layout_type' => 'accordion', ], 'accordionPadding' => [ 'func_build_responsive_style' => [ $this, 'build_accordion_padding_style' ], 'group' => 'accordion', 'setting_name' => 'padding', 'layout_type' => 'accordion', ], 'accordionBorder' => [ 'func_build_style' => [ $this, 'build_accordion_border_style' ], 'group' => 'accordion', 'setting_name' => 'border', 'layout_type' => 'accordion', ], 'accordionRadius' => [ 'func_build_style' => [ $this, 'build_accordion_radius_style' ], 'group' => 'accordion', 'setting_name' => 'radius', 'layout_type' => 'accordion', ], 'stickyOffset' => [ 'func_build_responsive_style' => [ $this, 'build_sticky_offset_style' ], 'group' => 'sticky', 'setting_name' => 'offset', ], ]; $block_layout = apply_filters( 'cbb_get_block_layout', $block_instance->block_type->supports['layoutType'] ?? '', $block ); foreach ( $features as $feature => $feature_args ) { if ( isset( $feature_args['layout_type'] ) && $block_layout !== $feature_args['layout_type'] ) { continue; } if ( ! in_array( $feature, [ 'border', 'hidden' ], true ) && 'accordionItem' === $block_layout ) { continue; } if ( ! in_array( $feature, [ 'border', 'hidden', 'accordionGap', 'accordionPadding', 'accordionBorder', 'accordionRadius' ], true ) && 'accordion' === $block_layout ) { continue; } if ( 'stickyOffset' === $feature ) { // Not supported block layouts. if ( ! in_array( $block_layout, [ 'standalone', 'gridItem' ], true ) ) { continue; } // Not enable sticky or enabling scrolling up. if ( ! ( $settings['sticky']['enable'] ?? false ) || ( $settings['sticky']['isStickOnScrollingUp'] ?? false ) ) { continue; } } $group_name = $feature_args['group'] ?? null; $setting_name = $feature_args['setting_name'] ?? $feature; if ( $this->is_valid_value( $group_name ) ) { $setting_value = $settings[ $group_name ][ $setting_name ] ?? null; } else { $setting_value = $settings[ $setting_name ] ?? null; } if ( empty( $setting_value ) ) { continue; } $args = array_merge( [ 'settings' => $settings, 'setting_value' => $setting_value, 'feature' => $feature, 'selector' => $class_selector, 'breakpoints' => $breakpoints, 'block' => $block, 'block_layout' => $block_layout, ], $feature_args ); if ( \is_callable( $args['func_build_style'] ?? '' ) ) { $this->build_style( array_merge( $args, [ 'value' => $setting_value ] ), $style_array, $classes ); } if ( \is_callable( $args['func_build_responsive_style'] ?? '' ) && $this->is_valid_responsive_value( $args['setting_value'] ) ) { $this->build_responsive_style( $args, $responsive_style_array, $classes ); } } if ( $style_array ) { foreach ( $style_array as $item_style ) { $style .= $item_style; } } if ( $responsive_style_array ) { foreach ( $responsive_style_array as $responsive_style ) { $style .= $responsive_style; } } $custom_css = $this->get_custom_css_style( $block ); if ( $custom_css ) { // Get & refine custom style. $custom_style = $this->refine_custom_value( $custom_css['value'] ?? '', [ 'selector' => $class_selector ], 'CSS' ); if ( $custom_style ) { $style .= $custom_style; } } // Allow altering the style. $style = apply_filters( 'cbb_get_block_style', $style, [ 'settings' => $settings, 'selector' => $class_selector, 'breakpoints' => $breakpoints, 'block' => $block, 'block_layout' => $block_layout, ] ); return [ 'style' => $style, 'classes' => $classes, ]; } /** * Build custom style * * @param array $args * @param array &$style_array * @param array &$classes * @return string */ private function build_style( $args, &$style_array, &$classes ) { $return_value = false; $func_build_style = $args['func_build_style'] ?? ''; if ( ! \is_callable( $func_build_style ) ) { return $return_value; } $setting_value = $args['setting_value'] ?? []; if ( ! $this->is_valid_value( $setting_value ) ) { return $return_value; } // Build style. return $func_build_style( $args, $style_array, $classes ); } /** * Build style for padding * * @param array $args * @return string */ private function build_padding_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) ) { if ( isset( $value['top'] ) && is_string( $value['top'] ) ) { $top_style = $this->get_spacing_value( $value['top'] ); if ( $this->is_valid_value( $top_style ) ) { $style_array['--cbb--padding-top'] = $top_style; } } if ( isset( $value['right'] ) && is_string( $value['right'] ) ) { $right_style = $this->get_spacing_value( $value['right'] ); if ( $this->is_valid_value( $right_style ) ) { $style_array['--cbb--padding-right'] = $right_style; } } if ( isset( $value['bottom'] ) && is_string( $value['bottom'] ) ) { $bottom_style = $this->get_spacing_value( $value['bottom'] ); if ( $this->is_valid_value( $bottom_style ) ) { $style_array['--cbb--padding-bottom'] = $bottom_style; } } if ( isset( $value['left'] ) && is_string( $value['left'] ) ) { $left_style = $this->get_spacing_value( $value['left'] ); if ( $this->is_valid_value( $left_style ) ) { $style_array['--cbb--padding-left'] = $left_style; } } } return $style_array; } /** * Build style for margin * * @param array $args * @return string */ private function build_margin_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) ) { if ( isset( $value['top'] ) && is_string( $value['top'] ) ) { $top_style = $this->get_spacing_value( $value['top'] ); if ( $this->is_valid_value( $top_style ) ) { $style_array['--cbb--margin-top'] = $top_style; } } if ( isset( $value['right'] ) && is_string( $value['right'] ) ) { $right_style = $this->get_spacing_value( $value['right'] ); if ( $this->is_valid_value( $right_style ) ) { $style_array['--cbb--margin-right'] = $right_style; } } if ( isset( $value['bottom'] ) && is_string( $value['bottom'] ) ) { $bottom_style = $this->get_spacing_value( $value['bottom'] ); if ( $this->is_valid_value( $bottom_style ) ) { $style_array['--cbb--margin-bottom'] = $bottom_style; } } if ( isset( $value['left'] ) && is_string( $value['left'] ) ) { $left_style = $this->get_spacing_value( $value['left'] ); if ( $this->is_valid_value( $left_style ) ) { $style_array['--cbb--margin-left'] = $left_style; } } } return $style_array; } /** * Build style for gap * * @param array $args * @return string */ private function build_block_gap_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) && ( $value['top'] ?? false ) ) { $gap_style = $this->get_spacing_value( $value['top'] ); if ( $this->is_valid_value( $gap_style ) ) { $style_array['--cbb--block-gap'] = $gap_style; } } return $style_array; } /** * Build style for border * * @param array $args * @return string */ private function build_border_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) ) { if ( ( $value['top'] ?? false ) || ( $value['right'] ?? false ) || ( $value['bottom'] ?? false ) || ( $value['left'] ?? false ) ) { $top = $value['top'] ?? null; $right = $value['right'] ?? null; $bottom = $value['bottom'] ?? null; $left = $value['left'] ?? null; } else { $top = $value; $right = $value; $bottom = $value; $left = $value; } if ( $top ) { $top_style = $this->build_border_side_css_value( $top, 'top' ); if ( $top_style ) { $style_array['--cbb--border-top'] = $top_style; } } if ( $right ) { $right_style = $this->build_border_side_css_value( $right, 'right' ); if ( $right_style ) { $style_array['--cbb--border-right'] = $right_style; } } if ( $bottom ) { $bottom_style = $this->build_border_side_css_value( $bottom, 'bottom' ); if ( $bottom_style ) { $style_array['--cbb--border-bottom'] = $bottom_style; } } if ( $left ) { $left_style = $this->build_border_side_css_value( $left, 'left' ); if ( $left_style ) { $style_array['--cbb--border-left'] = $left_style; } } } return $style_array; } /** * Build the css variable for border by side * * @param array $value * @param string $side * @return string */ private function build_border_side_css_value( $value, $side ) { $style_array = []; if ( is_array( $value ) ) { if ( $this->is_valid_value( $value['width'] ?? null ) && is_string( $value['width'] ) ) { $style_array[] = $value['width']; } if ( $this->is_valid_value( $value['style'] ?? null ) && is_string( $value['style'] ) ) { $style_array[] = $value['style']; } if ( $this->is_valid_value( $value['color'] ?? null ) ) { $color = $this->get_css_color_value( $value['color'] ); if ( $color ) { $style_array[] = $color; } } } return implode( ' ', $style_array ); } /** * Build style for radius * * @param array $args * @return string */ private function build_border_radius_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) ) { $css_value = ''; $top_left = $value['top-left'] ?? 0; $top_right = $value['top-right'] ?? 0; $bottom_right = $value['bottom-right'] ?? 0; $bottom_left = $value['bottom-left'] ?? 0; if ( ! empty( $top_left ) || ! empty( $top_right ) || ! empty( $bottom_right ) || ! empty( $bottom_left ) ) { $css_value = "{$top_left} {$top_right} {$bottom_right} {$bottom_left}"; } if ( $args['settings']['enableEllipticalRadius'] ?? false ) { $top_left = $value['top-left-vertical'] ?? 0; $top_right = $value['top-right-vertical'] ?? 0; $bottom_right = $value['bottom-right-vertical'] ?? 0; $bottom_left = $value['bottom-left-vertical'] ?? 0; if ( ! empty( $top_left ) || ! empty( $top_right ) || ! empty( $bottom_right ) || ! empty( $bottom_left ) ) { $css_value = "{$css_value} / {$top_left} {$top_right} {$bottom_right} {$bottom_left}"; } } if ( $css_value ) { $style_array['--cbb--border-radius'] = $css_value; } } return $style_array; } /** * Build style for width * * @param array $args * @return string */ private function build_width_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) && ( $value['value'] ?? false ) ) { $width_style = $value['value']; if ( $this->is_valid_value( $width_style ) ) { $style_array['--cbb--width'] = $width_style; } } return $style_array; } /** * Build style for height * * @param array $args * @return string */ private function build_height_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) && ( $value['value'] ?? false ) ) { $style = $value['value']; if ( $this->is_valid_value( $style ) ) { $style_array['--cbb--height'] = $style; } } return $style_array; } /** * Build style for aspect ratio * * @param array $args * @return string */ private function build_aspect_ratio_style( $args ) { $style_array = []; $value = $args['value']; if ( is_array( $value ) && ( $value['value'] ?? false ) ) { $style = $value['value']; if ( $this->is_valid_value( $style ) ) { $style_array['--cbb--aspect-ratio'] = $style; } } return $style_array; } /** * Build style for text alignment * * @param array $args * @return string */ private function build_text_align_style( $args ) { $style_array = []; $value = $args['value']; if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--text-align'] = $value; } return $style_array; } /** * Build style for vertical alignment * * @param array $args * @return string */ private function build_vertical_align_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $this->is_valid_value( $value ) ) { if ( 'top' === $value ) { $value = 'start'; } elseif ( 'bottom' === $value ) { $value = 'end'; } $style_array['--cbb--v-align'] = $value; } return $style_array; } /** * Build dependent style for vertical alignment * * @param array $args * @param array &$classes * @return string */ private function build_vertical_align_dependent_style( $args, &$classes ) { $style = ''; $value = $args['setting_value'] ?? null; if ( $this->is_valid_value( $value ) ) { $block_layout = $args['block_layout'] ?? ''; if ( 'grid' === $block_layout ) { $class = 'cbb-align-items'; } elseif ( 'gridItem' === $block_layout ) { $class = 'cbb-align-self'; } else { $class = 'cbb-layout-grid'; } if ( ! in_array( $class, $classes, true ) ) { $classes[] = $class; } } return $style; } /** * Build style for justify alignment * * @param array $args * @return string */ private function build_justify_align_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $this->is_valid_value( $value ) ) { $block_layout = $args['block_layout'] ?? ''; if ( in_array( $block_layout, [ 'standalone', 'carouselItem', 'vstackItem' ], true ) ) { if ( 'left' === $value ) { $value = 'start'; } elseif ( 'right' === $value ) { $value = 'end'; } } $style_array['--cbb--h-align'] = $value; } return $style_array; } /** * Build dependent style for justify alignment * * @param array $args * @param array &$classes * @return string */ private function build_justify_align_dependent_style( $args, &$classes ) { $style = ''; $value = $args['setting_value'] ?? null; if ( $this->is_valid_value( $value ) ) { $block_layout = $args['block_layout'] ?? ''; if ( 'grid' === $block_layout ) { $class = 'cbb-justify-items'; } elseif ( 'gridItem' === $block_layout ) { $class = 'cbb-justify-self'; } else { // if ( in_array( $block_layout, [ 'standalone', 'carouselItem', 'vstackItem' ], true ) ) {. $class = 'cbb-layout-grid'; } if ( ! in_array( $class, $classes, true ) ) { $classes[] = $class; } } return $style; } /** * Build style for transform * * @param array $args * @return string */ private function build_transform_style( $args ) { $style_array = []; $value = $args['value']; if ( ! empty( $value ) && is_array( $value ) ) { $style = implode( ' ', array_filter( array_map( [ $this, 'build_transform_item' ], $value ) ) ); if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--transform'] = $style; } } return $style_array; } /** * Build transform item: translate, rotate, scale, skew * * @return string */ private function build_transform_item( $transform_item ) { $style = ''; if ( is_array( $transform_item ) && count( $transform_item ) > 0 ) { // Get tranform type. $transform_type = array_keys( $transform_item )[0]; $transform_value = $transform_item[ $transform_type ] ?? ''; if ( $transform_type === 'rotate' ) { if ( is_numeric( $transform_value ) ) { $style = "rotate({$transform_value}deg)"; } } elseif ( is_array( $transform_value ) ) { $suffix = 'skew' === $transform_type ? 'deg' : ''; $x = $transform_value['x'] ?? ''; $y = $transform_value['y'] ?? ''; $x_value = preg_replace( '/[^0-9.]/', '', $x ); $y_value = preg_replace( '/[^0-9.]/', '', $y ); if ( \is_numeric( $x_value ) || \is_numeric( $y_value ) ) { if ( ! \is_numeric( $x_value ) ) { if ( 'scale' === $transform_type ) { $x = 1; } else { $x = 0; } } if ( ! \is_numeric( $y_value ) ) { if ( 'scale' === $transform_type ) { $y = 1; } else { $y = 0; } } $style = "{$transform_type}({$x}{$suffix}, {$y}{$suffix})"; } } } return $style; } /** * Build dependent style for transform * * @param array $args * @param array &$classes * @return string */ private function build_transform_dependent_style( $args, &$classes ) { $transform_origin = $args['settings']['transformOrigin'] ?? []; $x = $transform_origin['x'] ?? .5; if ( ! \is_numeric( $x ) ) { $x = .5; } $x = round( $x, 2 ) * 100; $y = $transform_origin['y'] ?? .5; if ( ! \is_numeric( $y ) ) { $y = .5; } $y = round( $y, 2 ) * 100; return "{$args['selector']}{--cbb--transform-origin: {$x}% {$y}%;}"; } /** * Build style for hidden * * @param array $args * @param array &$style_array * @param array &$classes * @return array */ private function build_hidden_style( $args, &$style_array, &$classes ) { $value = $args['value'] ?? null; if ( ! empty( $value ) && is_array( $value ) ) { foreach ( $value as $breakpoint ) { $class = "cbb-hidden-{$breakpoint}"; if ( ! in_array( $class, $classes, true ) ) { $classes[] = $class; } } } } /** * Build style for grid columns * * @param array $args * @return string */ private function build_columns_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--grid-columns'] = $value; } return $style_array; } /** * Build style for grid rows * * @param array $args * @return string */ private function build_rows_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--grid-rows'] = $value; } return $style_array; } /** * Build style for grid auto rows * * @param array $args * @return string */ private function build_auto_rows_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--grid-auto-rows'] = $value; } return $style_array; } /** * Build style for grid gap * * @param array $args * @return string */ private function build_gap_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $value && is_array( $value ) ) { $column_gap = $value['column'] ?? null; if ( $this->is_valid_value( $column_gap ) ) { $style_array['--cbb--grid-gap-column'] = $column_gap; } $row_gap = $value['row'] ?? null; if ( $this->is_valid_value( $row_gap ) ) { $style_array['--cbb--grid-gap-row'] = $row_gap; } } return $style_array; } /** * Build style for grid item column span * * @param array $args * @return string */ private function build_column_span_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $value && is_array( $value ) ) { $start = $value['start'] ?? null; $span = $value['span'] ?? null; $order = $value['order'] ?? null; if ( $this->is_valid_value( $start ) || $this->is_valid_value( $span ) ) { $start = $this->is_valid_value( $start ) ? $start : 'auto'; $span = $this->is_valid_value( $span ) ? $span : 'auto'; if ( 'auto' !== $span && absint( $span ) > 0 ) { $span = "span {$span}"; } $style_array['--cbb--grid-item-column'] = "{$start} / {$span}"; } if ( $this->is_valid_value( $order ) && $order !== 'auto' ) { $style_array['--cbb--grid-item-order'] = $order; } } return $style_array; } /** * Build style for grid item row span * * @param array $args * @return string */ private function build_row_span_style( $args ) { $style_array = []; $value = $args['value'] ?? null; if ( $value && is_array( $value ) ) { $start = $value['start'] ?? null; $span = $value['span'] ?? null; if ( $this->is_valid_value( $start ) || $this->is_valid_value( $span ) ) { $start = $this->is_valid_value( $start ) ? $start : 'auto'; $span = $this->is_valid_value( $span ) ? $span : 'auto'; if ( 'auto' !== $span && absint( $span ) > 0 ) { $span = "span {$span}"; } $style_array['--cbb--grid-item-row'] = "{$start} / {$span}"; } } return $style_array; } /** * Build style for accordion gap * * @param array $args * @return string */ private function build_accordion_gap_style( $args ) { $style_array = []; $value = $args['value']; if ( $this->is_valid_value( $value ) ) { $style_array['--cbb--accordion-gap'] = $this->get_spacing_value( $value ); } return $style_array; } /** * Build dependent style for accordion gap * * @param array $args * @param array &$classes * @return string */ private function build_accordion_gap_dependent_style( $args, &$classes ) { $style = ''; $setting_values = $args['setting_values']; if ( $this->is_valid_value( $setting_values ) && is_array( $setting_values ) ) { foreach ( $setting_values as $breakpoint => $value ) { if ( strpos( $value, 'var:preset|spacing|' ) !== false || absint( $value ) > 0 ) { $classes[] = "{$breakpoint}-cbb-a-has-border"; } else { $classes[] = "{$breakpoint}-cbb-a-no-border"; } } } return $style; } /** * Build style for accordion gap * * @param array $args * @return string */ private function build_accordion_padding_style( $args ) { $style_array = []; $value = $args['value']; if ( $value && is_array( $value ) ) { $x = $value['x'] ?? null; if ( ! $this->is_valid_value( $x ) ) { $x = '1.25rem'; } $x = $this->get_spacing_value( $x ); $y = $value['y'] ?? null; if ( ! $this->is_valid_value( $y ) ) { $y = '1rem'; } $y = $this->get_spacing_value( $y ); $style_array['--cbb--accordion-padding'] = "{$y} {$x}"; } return $style_array; } /** * Build style for accordion border * * @param array $args * @return string */ private function build_accordion_border_style( $args, &$style_array ) { $value = $args['value'] ?? null; if ( $value && is_array( $value ) ) { if ( ( $value['top'] ?? false ) || ( $value['right'] ?? false ) || ( $value['bottom'] ?? false ) || ( $value['left'] ?? false ) ) { $border_styles = $this->build_border_style( $args ); } else { $border_styles = $this->build_border_style( [ 'value' => [ 'top' => $value, 'right' => $value, 'bottom' => $value, 'left' => $value, ], ] ); } if ( $border_styles ) { $border_style = implode( ';', array_map( function ( $attr_key ) use ( $border_styles ) { return "{$attr_key}:{$border_styles[ $attr_key ]}"; }, array_keys( $border_styles ) ) ); $style_array[] = "{$args['selector']}{{$border_style};}"; } } return $style_array; } /** * Build style for accordion radius * * @param array $args * @return string */ private function build_accordion_radius_style( $args, &$style_array ) { $value = $args['value'] ?? null; if ( $value ) { if ( is_array( $value ) ) { $top_left = $value['topLeft'] ?? 0; $top_right = $value['topRight'] ?? 0; $bottom_right = $value['bottomRight'] ?? 0; $bottom_left = $value['bottomLeft'] ?? 0; $css_value = "{$top_left} {$top_right} {$bottom_right} {$bottom_left}"; } elseif ( is_string( $value ) ) { $css_value = $value; } $style_array[] = "{$args['selector']}{--cbb--border-radius:{$css_value};}"; } return $style_array; } /** * Build style for sticky offset * * @param array $args * @return array */ private function build_sticky_offset_style( $args ) { $style_array = []; $value = $args['value']; if ( $value && is_array( $value ) ) { $offset = $value['value'] ?? null; if ( $this->is_valid_value( $offset ) ) { $style_array['--cbb--sticky-offset'] = $offset; } } return $style_array; } /** * Check whether current block has custom style or not. * * @param [type] $block * @return boolean */ private function get_custom_css_style( $block ) { // There is no boldblocks value. if ( ! isset( $block['attrs']['boldblocks'] ) || ! isset( $block['attrs']['boldblocks']['customCSS'] ) ) { return false; } $custom_css = $block['attrs']['boldblocks']['customCSS']; if ( ! is_array( $custom_css ) || empty( $custom_css['value'] ) ) { return false; } return $custom_css; } /** * Render dynamic link to post element * * @param string $block_content * @param array $block * @param WP_Block $block_instance * @return string */ public function build_block_link_to_post( $block_content, $block, $block_instance ) { // Ignore admin side. if ( is_admin() ) { return $block_content; } // There is no post context. $post_id = $block_instance->context['postId'] ?? false; if ( ! $post_id ) { return $block_content; } // There is no background value. if ( ! ( $block['attrs']['boldblocks']['background'] ?? false ) ) { return $block_content; } $background = $block['attrs']['boldblocks']['background']; $media_type = $background['mediaType'] ?? 'image'; if ( 'image' === $media_type && ( $background['image']['useFeaturedImage'] ?? false ) && ( $background['image']['linkToPost'] ?? false ) ) { $block_content = $this->add_inner_content_to_block( $block_content, '' ); } return $block_content; } /** * Render dynamic background image * * @param string $block_content * @param array $block * @param WP_Block $block_instance * @return string */ public function build_block_background( $block_content, $block, $block_instance ) { // Ignore admin side. if ( is_admin() ) { return $block_content; } // Ignore legacy markup. if ( strpos( $block['innerHTML'] ?? '', 'bb:block-background' ) !== false ) { return $block_content; } $context_background = []; $meta_name = $block['attrs']['metadata']['name'] ?? ''; if ( $meta_name && 'cbb/block-overrides' === ( $block['attrs']['metadata']['bindings']['background']['source'] ?? '' ) ) { $context_background = $block_instance->context['cbb/block-overrides'][ $meta_name ]['background'] ?? []; } $background = $block['attrs']['boldblocks']['background'] ?? []; if ( $context_background ) { $background = array_replace_recursive( $background, $context_background ); } // There is no background value. if ( ! $background ) { return $block_content; } $media_type = $background['mediaType'] ?? 'image'; $media_url = $background[ $media_type ]['url'] ?? ''; if ( 'image' === $media_type ) { if ( $background['image']['useFeaturedImage'] ?? false ) { return $this->build_thumbnail_background( $background, $block_content, $block, $block_instance ); } elseif ( $media_url ) { return $this->build_custom_image_background( $background, $block_content, $block, $block_instance ); } } elseif ( 'video' === $media_type && $media_url ) { return $this->build_video_background( $background, $block_content, $block, $block_instance ); } return $block_content; } /** * Build the background using custom image * * @param array $background * @param string $block_content * @param array $block * @param WP_Block $block_instance * @return string */ private function build_custom_image_background( $background, $block_content, $block, $block_instance ) { $block_class = 'bb:has-background bb:has-background--image'; $block_background = $this->build_image_background( $background['image']['id'] ?? false, $background, $block_class ); if ( strpos( $block['innerHTML'] ?? '', $block_background['block_class'] ) === false ) { $block_content = $this->add_class_to_block( $block_content, $block_background['block_class'] ); } $block_content = $this->add_inner_content_to_block( $block_content, $block_background['background_markup'] ); return $block_content; } /** * Build the background using post thumbnail * * @param array $background * @param string $block_content * @param array $block * @param WP_Block $block_instance * @return string */ private function build_thumbnail_background( $background, $block_content, $block, $block_instance ) { $post_id = $block_instance->context['postId'] ?? false; if ( ! $post_id ) { return $block_content; } $image_id = get_post_thumbnail_id( $post_id ); $block_class = 'bb:has-background bb:has-background--image'; if ( $image_id ) { $block_background = $this->build_image_background( $image_id, $background, $block_class ); if ( strpos( $block['innerHTML'] ?? '', $block_background['block_class'] ) === false ) { $block_content = $this->add_class_to_block( $block_content, $block_background['block_class'] ); } $block_content = $this->add_inner_content_to_block( $block_content, $block_background['background_markup'] ); } else { // Add custom background as a fallback. if ( $background['image']['url'] ?? '' ) { $block_content = $this->add_class_to_block( $block_content, 'has-no-thumbnail' ); $block_content = $this->build_custom_image_background( $background, $block_content, $block, $block_instance ); } else { $block_content = $this->add_class_to_block( $block_content, $block_class . ' has-no-thumbnail' ); } } return $block_content; } /** * Build image background * * @param int $image_id * @param array $background * @param string $block_class * @return array */ private function build_image_background( $image_id, $background, $block_class ) { $settings = $background['settings'] ?? []; $media = $background['image'] ?? []; $mobile_background = ! ( $media['useFeaturedImage'] ?? false ) && ( $media['hasMobileBackground'] ?? false ) && ( $media['mobileBackground']['url'] ?? '' ) ? $media['mobileBackground'] : false; $background_classes = [ 'bb:block-background bb:block-background--image cbb-bg-image' ]; $background_position = round( ( $settings['focalPoint']['x'] ?? .5 ) * 100 ) . '% ' . round( ( $settings['focalPoint']['y'] ?? .5 ) * 100 ) . '%'; $image_element = ''; $dataset = []; $image_size = $media['size'] ?? 'full'; $is_internal_image = false; $image_url = $image_id ? wp_get_attachment_image_url( $image_id, $image_size ) : false; if ( $image_url ) { $is_internal_image = true; } else { $image_url = $media['url'] ?? ''; } $custom_alt_text = $media['customAlt'] ?? ''; $object_fit = $settings['objectFit'] ?? 'cover'; if ( empty( $object_fit ) ) { $object_fit = 'cover'; } $img_style = 'display:block;width:100%;height:100%;object-fit:' . $object_fit . ';object-position:' . $background_position . ';'; $background_styles = []; if ( $settings['isImgElement'] ?? false ) { $attrs = [ 'style' => esc_attr( $img_style ), 'class' => 'bb:block-background--img', ]; $loading_priority = $settings['loadingPriority'] ?? ''; if ( $loading_priority ) { if ( $loading_priority === 'lazy' ) { $attrs['loading'] = 'lazy'; } elseif ( in_array( $loading_priority, [ 'high', 'low' ], true ) ) { $attrs['fetchpriority'] = $loading_priority; } } if ( $is_internal_image ) { $alt = trim( wp_strip_all_tags( get_post_meta( $image_id, '_wp_attachment_image_alt', true ) ) ); if ( ! $alt ) { $attrs['alt'] = $custom_alt_text; } $image_element = wp_get_attachment_image( $image_id, $image_size, false, $attrs ); } else { $image_element = $this->generate_image_element( $image_url, array_merge( $attrs, [ 'alt' => $custom_alt_text ] ) ); } if ( $mobile_background ) { $background_classes[] = 'cbb-mobile-image'; $attrs['class'] .= ' is-mobile-image'; $mobile_image = ''; if ( $mobile_background['id'] ?? false ) { $alt = trim( wp_strip_all_tags( get_post_meta( $mobile_background['id'], '_wp_attachment_image_alt', true ) ) ); $attrs['alt'] = $alt ? $alt : $custom_alt_text; $mobile_image = wp_get_attachment_image( $mobile_background['id'], $image_size, false, $attrs ); } if ( ! $mobile_image ) { $mobile_image = $this->generate_image_element( $mobile_background['url'], array_merge( $attrs, [ 'alt' => $custom_alt_text ] ) ); } $image_element .= $mobile_image; } } else { $image_as_background = $this->get_background_image_url( $image_url ); $background_styles = [ 'background-image' => 'url(' . $image_as_background . ')', 'background-position' => $background_position, ]; if ( ! empty( $settings['isFixed'] ) ) { $background_styles['background-attachment'] = 'fixed'; } $background_styles['background-repeat'] = $settings['repeat'] ?? 'no-repeat'; $background_styles['background-size'] = $settings['size'] ?? 'cover'; if ( $mobile_background ) { $background_styles['--cbb-mobile-background'] = "url('{$this->get_background_image_url( $mobile_background['url'] )}')"; $background_classes[] = 'cbb-mobile-background'; } } $animation_type = $settings['animation']['type'] ?? ''; $animation_settings = $settings['animation']['settings'] ?? []; if ( $animation_type && 'none' !== $animation_type ) { $background_classes[] = $animation_type; if ( in_array( $animation_type, [ 'bg-scroll-horizontal', 'bg-scroll-vertical' ], true ) ) { if ( ! ( $settings['isImgElement'] ?? false ) ) { if ( $this->has_animation_setting_value( 'scroll', 'duration', $animation_settings ) ) { $background_styles['animation-duration'] = $this->get_animation_setting_value( 'scroll', 'duration', $animation_settings ) . 's'; } if ( $background_styles['background-repeat'] !== 'repeat' ) { $background_styles['background-repeat'] = 'bg-scroll-horizontal' === $animation_type ? 'repeat-x' : 'repeat-y'; } if ( $this->has_animation_setting_value( 'scroll', 'reverseDirection', $animation_settings ) ) { $background_classes[] = 'is-reverse'; } } } elseif ( 'bg-parallax' === $animation_type ) { unset( $background_styles['background-attachment'] ); $dataset['data-speed'] = $this->get_animation_setting_value( 'parallax', 'speed', $animation_settings, 0.5 ); if ( $this->get_animation_setting_value( 'parallax', 'opacity', $animation_settings, '' ) ) { $dataset['data-opacity'] = 'true'; } if ( $this->get_animation_setting_value( 'parallax', 'disableParallax', $animation_settings, '' ) ) { $dataset['data-disable-parallax'] = 'true'; $breakpoint = $this->get_animation_setting_value( 'parallax', 'disableParallaxBreakpoint', $animation_settings ); if ( ! $breakpoint ) { $breakpoint = 767; } $dataset['data-disable-parallax-breakpoint'] = $breakpoint; } } elseif ( 'bg-zoom' === $animation_type ) { if ( isset( $animation_settings['zoom']['initialScale'] ) ) { $background_styles['--cbb--zoom-initial-scale'] = $animation_settings['zoom']['initialScale']; } if ( isset( $animation_settings['zoom']['scale'] ) ) { $background_styles['--cbb--zoom-scale'] = $animation_settings['zoom']['scale']; } if ( isset( $animation_settings['zoom']['duration'] ) ) { $background_styles['--cbb--zoom-duration'] = $animation_settings['zoom']['duration'] . 's'; } if ( isset( $animation_settings['zoom']['timingFunction'] ) ) { $background_styles['--cbb--zoom-timing-function'] = $animation_settings['zoom']['timingFunction']; } $zoom_event = $animation_settings['zoom']['event'] ?? 'hover'; $background_classes[] = "bg-zoom-{$zoom_event}"; if ( 'reveal' === $zoom_event ) { $dataset['data-reveal-animation'] = esc_attr( wp_json_encode( [ 'name' => 'bgZoom', 'animation' => 'bgZoom var(--cbb--zoom-duration) var(--cbb--zoom-timing-function)', 'multipleTimes' => $animation_settings['zoom']['multipleTimes'] ?? false, 'forwards' => true, ] ) ); } if ( ! empty( $animation_settings['zoom']['withOpacity'] ) ) { $background_styles['--cbb--zoom-initial-opacity'] = $animation_settings['zoom']['initialOpacity'] ?? 0; $background_styles['--cbb--zoom-opacity'] = $animation_settings['zoom']['opacity'] ?? 1; } } elseif ( 'bg-zoomIn' === $animation_type ) { if ( isset( $animation_settings['zoomIn']['initialScale'] ) ) { $background_styles['--cbb--zoom-initial-scale'] = $animation_settings['zoomIn']['initialScale']; } if ( isset( $animation_settings['zoomIn']['duration'] ) ) { $background_styles['--cbb--zoom-duration'] = $animation_settings['zoomIn']['duration'] . 's'; } if ( isset( $animation_settings['zoomIn']['timingFunction'] ) ) { $background_styles['--cbb--zoom-timing-function'] = $animation_settings['zoomIn']['timingFunction']; } if ( ! empty( $animation_settings['zoomIn']['withOpacity'] ) ) { $background_styles['--cbb--zoom-initial-opacity'] = $animation_settings['zoomIn']['initialOpacity'] ?? 0; $background_styles['--cbb--zoom-opacity'] = $animation_settings['zoomIn']['opacity'] ?? 1; } $dataset['data-reveal-animation'] = esc_attr( wp_json_encode( [ 'name' => 'bgZoomIn', 'animation' => 'bgZoomIn var(--cbb--zoom-duration) var(--cbb--zoom-timing-function)', 'multipleTimes' => $animation_settings['zoomIn']['multipleTimes'] ?? false, 'forwards' => true, ] ) ); } } $background_style = $background_styles ? array_reduce( array_keys( $background_styles ), function ( $carry, $key ) use ( $background_styles ) { return $carry . $key . ':' . $background_styles[ $key ] . ';'; }, '' ) : ''; if ( $background_style ) { $background_style = ' style="' . $background_style . '"'; } // Get image full size. $image_full_size = $is_internal_image ? $this->generate_image_full_attributes( $image_id ) : false; $dataset['data-src'] = $image_full_size ? $image_full_size['src'] : $image_url; if ( $image_full_size ) { $dataset['data-width'] = $image_full_size['width']; $dataset['data-height'] = $image_full_size['height']; } $data_attribute = $dataset ? array_reduce( array_keys( $dataset ), function ( $carry, $key ) use ( $dataset ) { return $carry . ' ' . $key . '="' . esc_attr( $dataset[ $key ] ) . '"'; }, ' ' ) : ''; $background_image = sprintf( '