| 1 |
<?php |
| 2 |
/** |
| 3 |
* Slide block server-side renderer. |
| 4 |
* Outputs a swiper-slide div with background, overlay, and content. |
| 5 |
* |
| 6 |
* @package Sliderberg |
| 7 |
*/ |
| 8 |
|
| 9 |
if ( ! defined( 'WPINC' ) ) { |
| 10 |
die; |
| 11 |
} |
| 12 |
|
| 13 |
/** |
| 14 |
* Register the slide block with PHP rendering. |
| 15 |
*/ |
| 16 |
function sliderberg_register_slide_block() { |
| 17 |
register_block_type_from_metadata( |
| 18 |
SLIDERBERG_PLUGIN_DIR . 'build/blocks/slide', |
| 19 |
array( |
| 20 |
'render_callback' => 'render_sliderberg_slide_block', |
| 21 |
) |
| 22 |
); |
| 23 |
} |
| 24 |
|
| 25 |
/** |
| 26 |
* Render the slide block on the frontend. |
| 27 |
* |
| 28 |
* @param array $attributes Block attributes. |
| 29 |
* @param string $content Inner block content. |
| 30 |
* @param WP_Block $block Block instance. |
| 31 |
* @return string HTML output. |
| 32 |
*/ |
| 33 |
function render_sliderberg_slide_block( $attributes, $content, $block ) { |
| 34 |
// The slider minimum height is the floor for every slide. A slide-specific |
| 35 |
// value can make the slide taller, but cannot make it shorter than the |
| 36 |
// parent slider and expose empty space below it. |
| 37 |
$parent_min_height = isset( $block->context['sliderberg/minHeight'] ) ? absint( $block->context['sliderberg/minHeight'] ) : 400; |
| 38 |
$slide_min_height = isset( $attributes['minHeight'] ) ? absint( $attributes['minHeight'] ) : 400; |
| 39 |
$effective_height = ( $slide_min_height !== 400 ) ? max( $slide_min_height, $parent_min_height ) : $parent_min_height; |
| 40 |
$transition_effect = isset( $block->context['sliderberg/transitionEffect'] ) ? $block->context['sliderberg/transitionEffect'] : 'slide'; |
| 41 |
$is_parallax = 'parallax' === $transition_effect; |
| 42 |
|
| 43 |
// Background — infer type from values so backgroundType doesn't need to be kept in sync |
| 44 |
$bg_styles = array(); |
| 45 |
|
| 46 |
if ( ! empty( $attributes['backgroundImage']['url'] ) ) { |
| 47 |
$bg_url = esc_url( $attributes['backgroundImage']['url'] ); |
| 48 |
$focal_x = isset( $attributes['focalPoint']['x'] ) ? floatval( $attributes['focalPoint']['x'] ) * 100 : 50; |
| 49 |
$focal_y = isset( $attributes['focalPoint']['y'] ) ? floatval( $attributes['focalPoint']['y'] ) * 100 : 50; |
| 50 |
$is_fixed = ! empty( $attributes['isFixed'] ); |
| 51 |
|
| 52 |
$bg_styles[] = sprintf( 'background-image:url(%s)', $bg_url ); |
| 53 |
$bg_styles[] = 'background-size:cover'; |
| 54 |
$bg_styles[] = sprintf( 'background-position:%s%% %s%%', $focal_x, $focal_y ); |
| 55 |
$bg_styles[] = 'background-repeat:no-repeat'; |
| 56 |
$bg_styles[] = sprintf( 'background-attachment:%s', $is_fixed ? 'fixed' : 'scroll' ); |
| 57 |
} elseif ( ! empty( $attributes['backgroundGradient'] ) ) { |
| 58 |
$bg_styles[] = sprintf( 'background-image:%s', esc_attr( $attributes['backgroundGradient'] ) ); |
| 59 |
} elseif ( ! empty( $attributes['backgroundColor'] ) ) { |
| 60 |
$bg_styles[] = sprintf( 'background-color:%s', esc_attr( $attributes['backgroundColor'] ) ); |
| 61 |
} |
| 62 |
|
| 63 |
// Border (new per-side format) |
| 64 |
$border = isset( $attributes['border'] ) ? $attributes['border'] : array(); |
| 65 |
$border_styles = array(); |
| 66 |
if ( is_array( $border ) && ! empty( $border ) ) { |
| 67 |
$sides = array( 'top', 'right', 'bottom', 'left' ); |
| 68 |
foreach ( $sides as $side ) { |
| 69 |
if ( ! empty( $border[ $side ] ) ) { |
| 70 |
$b = $border[ $side ]; |
| 71 |
$width = isset( $b['width'] ) ? esc_attr( $b['width'] ) : '0px'; |
| 72 |
$style = isset( $b['style'] ) ? esc_attr( $b['style'] ) : 'solid'; |
| 73 |
$color = isset( $b['color'] ) ? esc_attr( $b['color'] ) : 'transparent'; |
| 74 |
$border_styles[] = sprintf( 'border-%s:%s %s %s', $side, $width, $style, $color ); |
| 75 |
} |
| 76 |
} |
| 77 |
} |
| 78 |
|
| 79 |
// Border radius (new per-corner format) |
| 80 |
$border_radius = isset( $attributes['slideBorderRadius'] ) ? $attributes['slideBorderRadius'] : array(); |
| 81 |
$radius_styles = array(); |
| 82 |
if ( is_array( $border_radius ) && ! empty( $border_radius ) ) { |
| 83 |
$corners = array( |
| 84 |
'topLeft' => 'border-top-left-radius', |
| 85 |
'topRight' => 'border-top-right-radius', |
| 86 |
'bottomLeft' => 'border-bottom-left-radius', |
| 87 |
'bottomRight' => 'border-bottom-right-radius', |
| 88 |
); |
| 89 |
foreach ( $corners as $key => $prop ) { |
| 90 |
if ( ! empty( $border_radius[ $key ] ) ) { |
| 91 |
$radius_styles[] = sprintf( '%s:%s', $prop, esc_attr( $border_radius[ $key ] ) ); |
| 92 |
} |
| 93 |
} |
| 94 |
} |
| 95 |
|
| 96 |
// Content position |
| 97 |
$position = isset( $attributes['contentPosition'] ) ? $attributes['contentPosition'] : 'center-center'; |
| 98 |
$valid_positions = array( |
| 99 |
'top-left', 'top-center', 'top-right', |
| 100 |
'center-left', 'center-center', 'center-right', |
| 101 |
'bottom-left', 'bottom-center', 'bottom-right', |
| 102 |
); |
| 103 |
if ( ! in_array( $position, $valid_positions, true ) ) { |
| 104 |
$position = 'center-center'; |
| 105 |
} |
| 106 |
|
| 107 |
// The content wrapper below uses flex-direction:column, so align-items |
| 108 |
// controls the horizontal axis and justify-content controls the |
| 109 |
// vertical axis. |
| 110 |
$parts = explode( '-', $position ); |
| 111 |
$vertical = isset( $parts[0] ) ? $parts[0] : 'center'; |
| 112 |
$horizontal = isset( $parts[1] ) ? $parts[1] : 'center'; |
| 113 |
$align_items = 'center' === $horizontal ? 'center' : ( 'left' === $horizontal ? 'flex-start' : 'flex-end' ); |
| 114 |
$justify_content = 'center' === $vertical ? 'center' : ( 'top' === $vertical ? 'flex-start' : 'flex-end' ); |
| 115 |
|
| 116 |
// Combine all slide styles |
| 117 |
$base_slide_styles = array_merge( |
| 118 |
$border_styles, |
| 119 |
$radius_styles, |
| 120 |
array( sprintf( 'min-height:%dpx', $effective_height ) ) |
| 121 |
); |
| 122 |
|
| 123 |
if ( $is_parallax ) { |
| 124 |
$slide_style_str = implode( ';', $base_slide_styles ); |
| 125 |
} else { |
| 126 |
$slide_style_str = implode( ';', array_merge( $bg_styles, $base_slide_styles ) ); |
| 127 |
} |
| 128 |
|
| 129 |
// Content styles |
| 130 |
$content_style = sprintf( |
| 131 |
'display:flex;flex-direction:column;align-items:%s;justify-content:%s;min-height:%dpx;padding:20px;width:100%%;box-sizing:border-box;', |
| 132 |
$align_items, |
| 133 |
$justify_content, |
| 134 |
$effective_height |
| 135 |
); |
| 136 |
|
| 137 |
// Overlay |
| 138 |
$overlay_html = ''; |
| 139 |
$overlay_color = isset( $attributes['overlayColor'] ) ? $attributes['overlayColor'] : ''; |
| 140 |
$has_image = ! empty( $attributes['backgroundImage']['url'] ); |
| 141 |
if ( ! empty( $overlay_color ) && $has_image ) { |
| 142 |
$overlay_opacity = isset( $attributes['overlayOpacity'] ) ? floatval( $attributes['overlayOpacity'] ) : 1; |
| 143 |
if ( $overlay_opacity <= 0 ) { |
| 144 |
$overlay_opacity = 1; |
| 145 |
} |
| 146 |
$overlay_html = sprintf( |
| 147 |
'<div class="sliderberg-slide-overlay" style="position:absolute;top:0;left:0;right:0;bottom:0;background-color:%s;opacity:%s;pointer-events:none;z-index:1;"></div>', |
| 148 |
esc_attr( $overlay_color ), |
| 149 |
$overlay_opacity |
| 150 |
); |
| 151 |
} |
| 152 |
|
| 153 |
$background_html = ''; |
| 154 |
if ( $is_parallax && ! empty( $bg_styles ) ) { |
| 155 |
$background_html = sprintf( |
| 156 |
'<div class="sliderberg-slide-background" style="%1$s;position:absolute;top:0;left:0;right:0;bottom:0;" data-swiper-parallax="-20%%"></div>', |
| 157 |
esc_attr( implode( ';', $bg_styles ) ) |
| 158 |
); |
| 159 |
} |
| 160 |
|
| 161 |
// Slide link |
| 162 |
$slide_link = isset( $attributes['slideLink'] ) ? esc_url( $attributes['slideLink'] ) : ''; |
| 163 |
$slide_link_new_tab = ! empty( $attributes['slideLinkNewTab'] ); |
| 164 |
$slide_link_attrs = ''; |
| 165 |
$slide_link_style = ''; |
| 166 |
if ( ! empty( $slide_link ) ) { |
| 167 |
$slide_link_attrs = sprintf( |
| 168 |
' data-slide-link="%s" data-slide-link-target="%s"', |
| 169 |
$slide_link, |
| 170 |
$slide_link_new_tab ? '_blank' : '_self' |
| 171 |
); |
| 172 |
$slide_link_style = 'cursor:pointer;'; |
| 173 |
} |
| 174 |
|
| 175 |
// Build slide classes |
| 176 |
$slide_classes = 'swiper-slide sliderberg-slide'; |
| 177 |
$slide_classes = apply_filters( 'sliderberg_slide_classes', $slide_classes, $attributes ); |
| 178 |
|
| 179 |
$content_parallax_attr = $is_parallax ? ' data-swiper-parallax="-100"' : ''; |
| 180 |
|
| 181 |
return sprintf( |
| 182 |
'<div class="%1$s" style="%2$s;position:relative;overflow:hidden;%8$s"%9$s>%3$s%4$s<div class="sliderberg-slide-content" style="%5$s;position:relative;z-index:2;"%6$s>%7$s</div></div>', |
| 183 |
esc_attr( $slide_classes ), |
| 184 |
esc_attr( $slide_style_str ), |
| 185 |
$background_html, |
| 186 |
$overlay_html, |
| 187 |
esc_attr( $content_style ), |
| 188 |
$content_parallax_attr, |
| 189 |
$content, |
| 190 |
esc_attr( $slide_link_style ), |
| 191 |
$slide_link_attrs |
| 192 |
); |
| 193 |
} |
| 194 |
|