PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.16.0
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.16.0
2.16.0 2.15.0 2.14.0 2.13.0 2.13.1 2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 All 83 releases
← All changes | includes/blocks/price-menu-item/block.php +352 -0 2.7.4 → 2.16.0 View file →
@@ -1,0 +1,352 @@
1 +<?php
2 +namespace ABlocks\Blocks\PriceMenuItem;
3 +
4 +if ( ! defined( 'ABSPATH' ) ) {
5 + exit;
6 +}
7 +
8 +use ABlocks\Classes\BlockBaseAbstract;
9 +use ABlocks\Classes\CssGenerator;
10 +use ABlocks\Controls\Icon;
11 +use ABlocks\Controls\Alignment;
12 +use ABlocks\Controls\Typography;
13 +use ABlocks\Controls\TextShadow;
14 +use ABlocks\Controls\TextStroke;
15 +use ABlocks\Controls\Range;
16 +use ABlocks\Controls\Color;
17 +use ABlocks\Helper;
18 +
19 +class Block extends BlockBaseAbstract {
20 + protected $parent_block_name = 'price-menu';
21 + protected $block_name = 'price-menu-item';
22 +
23 + public function build_css( $attributes ) {
24 +
25 + $css_generator = new CssGenerator( $attributes, $this->block_name );
26 + // Icon Style
27 + $css_generator->add_class_styles(
28 + '{{WRAPPER}} .ablocks-icon-wrap',
29 + Icon::get_wrapper_css( $attributes ),
30 + Icon::get_wrapper_css( $attributes, 'Tablet' ),
31 + Icon::get_wrapper_css( $attributes, 'Mobile' ),
32 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_wrapper_css( $attributes, $device ); } )
33 + );
34 + $css_generator->add_class_styles(
35 + '{{WRAPPER}} .ablocks-icon-wrap:hover',
36 + Icon::get_wrapper_hover_css( $attributes ),
37 + Icon::get_wrapper_hover_css( $attributes, 'Tablet' ),
38 + Icon::get_wrapper_hover_css( $attributes, 'Mobile' ),
39 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_wrapper_hover_css( $attributes, $device ); } )
40 + );
41 + $css_generator->add_class_styles(
42 + '{{WRAPPER}} .ablocks-icon-wrap img.ablocks-image-icon',
43 + Icon::get_element_image_css( $attributes ),
44 + Icon::get_element_image_css( $attributes, 'Tablet' ),
45 + Icon::get_element_image_css( $attributes, 'Mobile' ),
46 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_css( $attributes, $device ); } )
47 + );
48 + $css_generator->add_class_styles(
49 + '{{WRAPPER}} .ablocks-icon-wrap img.ablocks-image-icon:hover',
50 + Icon::get_element_image_hover_css( $attributes ),
51 + Icon::get_element_image_hover_css( $attributes, 'Tablet' ),
52 + Icon::get_element_image_hover_css( $attributes, 'Mobile' ),
53 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_hover_css( $attributes, $device ); } )
54 + );
55 + $css_generator->add_class_styles(
56 + '{{WRAPPER}} .ablocks-icon-wrap svg.ablocks-svg-icon',
57 + Icon::get_element_css( $attributes ),
58 + Icon::get_element_css( $attributes, 'Tablet' ),
59 + Icon::get_element_css( $attributes, 'Mobile' ),
60 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_css( $attributes, $device ); } )
61 + );
62 + $css_generator->add_class_styles(
63 + '{{WRAPPER}} .ablocks-icon-wrap svg.ablocks-svg-icon:hover',
64 + Icon::get_element_image_hover_css( $attributes ),
65 + Icon::get_element_image_hover_css( $attributes, 'Tablet' ),
66 + Icon::get_element_image_hover_css( $attributes, 'Mobile' ),
67 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_hover_css( $attributes, $device ); } )
68 + );
69 + // TitleText CSS
70 + $css_generator->add_class_styles(
71 + '{{WRAPPER}} .ablocks-price-menu-item-details-title',
72 + $this->get_title_text_css( $attributes, '' ),
73 + $this->get_title_text_css( $attributes, 'Tablet' ),
74 + $this->get_title_text_css( $attributes, 'Mobile' ),
75 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_title_text_css( $attributes, $device ); } )
76 + );
77 + // DescriptionText CSS
78 + $css_generator->add_class_styles(
79 + '{{WRAPPER}} .ablocks-price-menu-item-details-des',
80 + $this->get_description_text_css( $attributes, '' ),
81 + $this->get_description_text_css( $attributes, 'Tablet' ),
82 + $this->get_description_text_css( $attributes, 'Mobile' ),
83 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_description_text_css( $attributes, $device ); } )
84 + );
85 + // SeparatorText CSS
86 + $css_generator->add_class_styles(
87 + '{{WRAPPER}} .ablocks-price-menu-divider__pattern-' . ( $attributes['dividerType'] === 'mask-style' ? 'mask' : 'css' ),
88 + $this->get_divider_css( $attributes, '' ),
89 + $this->get_divider_css( $attributes, 'Tablet' ),
90 + $this->get_divider_css( $attributes, 'Mobile' ),
91 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_divider_css( $attributes, $device ); } )
92 + );
93 + // PriceText CSS
94 + $css_generator->add_class_styles(
95 + '{{WRAPPER}} .ablocks-price-menu-item-price',
96 + $this->get_price_text_css( $attributes, '' ),
97 + $this->get_price_text_css( $attributes, 'Tablet' ),
98 + $this->get_price_text_css( $attributes, 'Mobile' ),
99 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_price_text_css( $attributes, $device ); } )
100 + );
101 + // Divider width (item override of the parent's width)
102 + $css_generator->add_class_styles(
103 + '{{WRAPPER}} .ablocks-divider',
104 + self::get_divider_width_css( $attributes, '' ),
105 + self::get_divider_width_css( $attributes, 'Tablet' ),
106 + self::get_divider_width_css( $attributes, 'Mobile' ),
107 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return self::get_divider_width_css( $attributes, $device ); } )
108 + );
109 + $css_generator->add_class_styles(
110 + '{{WRAPPER}} .ablocks-price-menu-item',
111 + self::get_item_width_css( $attributes, '' ),
112 + self::get_item_width_css( $attributes, 'Tablet' ),
113 + self::get_item_width_css( $attributes, 'Mobile' ),
114 + $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return self::get_item_width_css( $attributes, $device ); } )
115 + );
116 + $css_generator->add_class_styles(
117 + '{{WRAPPER}} .ablocks-price-menu-item-details-brief > .ablocks-price-menu-item-price',
118 + self::get_price_row_css( $attributes )
119 + );
120 + // Responsive placements: hide the slots not used on each device.
121 + foreach ( [
122 + 'divider' => isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '',
123 + 'price' => isset( $attributes['placePrice'] ) ? $attributes['placePrice'] : '',
124 + ] as $kind => $placement ) {
125 + foreach ( self::get_used_placements( $placement ) as $slot ) {
126 + $css_generator->add_class_styles(
127 + '{{WRAPPER}} .' . self::get_slot_class_name( $kind, $slot ),
128 + self::get_slot_css( $placement, $slot, '' ),
129 + self::get_slot_css( $placement, $slot, 'Tablet' ),
130 + self::get_slot_css( $placement, $slot, 'Mobile' ),
131 + $css_generator->custom_device_map( function ( $device ) use ( $placement, $slot ) { return self::get_slot_css( $placement, $slot, $device ); } )
132 + );
133 + }
134 + }
135 +
136 + return $css_generator->generate_css();
137 + }
138 +
139 + /**
140 + * Divider width as a custom property; mirrors get_divider_width_css() in
141 + * src/blocks/price-menu-item/styling.js. The parent passes its own property
142 + * and default. A width without a stored unit keeps the legacy unit: % with a
143 + * description, px without.
144 + */
145 + public static function get_divider_width_css( $attributes, $device = '', $property = '--ablocks-pm-item-divider-width', $default_value = null ) {
146 + return Range::get_css([
147 + 'attributeValue' => isset( $attributes['width'] ) ? $attributes['width'] : [],
148 + 'attributeObjectKey' => 'value',
149 + 'isResponsive' => true,
150 + 'defaultValue' => $default_value,
151 + 'hasUnit' => true,
152 + 'unitDefaultValue' => ! empty( $attributes['allowDescription'] ) ? '%' : 'px',
153 + 'property' => $property,
154 + 'device' => $device,
155 + ]);
156 + }
157 +
158 + // A responsive member for the device, inherited from wider devices; '' when unset.
159 + private static function resolve_member( $value, $key, $device ) {
160 + $target = 'Desktop' === $device ? '' : (string) $device;
161 + foreach ( array_merge( [ $target ], Helper::get_responsive_ancestors( $target ) ) as $suffix ) {
162 + $member = is_array( $value ) && isset( $value[ $key . $suffix ] ) && ! is_array( $value[ $key . $suffix ] ) ? (string) $value[ $key . $suffix ] : '';
163 + if ( Helper::has_responsive_value( $member ) ) {
164 + return $member;
165 + }
166 + }
167 + return '';
168 + }
169 +
170 + // A % Title & price gap in effect on this device (unit default px).
171 + public static function is_percent_title_price_gap( $attributes, $device = '' ) {
172 + $gap = isset( $attributes['titlePriceGap'] ) ? $attributes['titlePriceGap'] : [];
173 + return '' !== self::resolve_member( $gap, 'value', $device ) && '%' === Range::get_unit( [
174 + 'attributeValue' => $gap,
175 + 'attributeObjectKey' => 'value',
176 + 'unitDefaultValue' => 'px',
177 + 'device' => $device,
178 + ] );
179 + }
180 +
181 + // A % on the title row; mirrors isPercentTitleRow() in styling.js. The legacy
182 + // implicit % (Allow description, no stored unit) is left alone.
183 + public static function is_percent_title_row( $attributes, $device = '' ) {
184 + return self::is_percent_title_price_gap( $attributes, $device ) || (
185 + ! empty( $attributes['allowDivider'] ) &&
186 + 'near title' === self::get_placement( isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '', $device ) &&
187 + '%' === self::resolve_member( isset( $attributes['width'] ) ? $attributes['width'] : [], 'valueUnit', $device )
188 + );
189 + }
190 +
191 + private static function has_percent_unit( $value ) {
192 + if ( ! is_array( $value ) ) {
193 + return false;
194 + }
195 + foreach ( $value as $key => $member ) {
196 + if ( 0 === strpos( $key, 'valueUnit' ) && '%' === $member ) {
197 + return true;
198 + }
199 + }
200 + return false;
201 + }
202 +
203 + public static function has_percent_title_price_gap( $attributes ) {
204 + return self::has_percent_unit( isset( $attributes['titlePriceGap'] ) ? $attributes['titlePriceGap'] : [] );
205 + }
206 +
207 + // Whether any device can use the % title row, so narrower devices that do
208 + // not must reset the item width they would otherwise inherit.
209 + public static function has_percent_title_row( $attributes ) {
210 + return self::has_percent_title_price_gap( $attributes ) || (
211 + ! empty( $attributes['allowDivider'] ) &&
212 + in_array( 'near title', self::get_used_placements( isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '' ), true ) &&
213 + self::has_percent_unit( isset( $attributes['width'] ) ? $attributes['width'] : [] )
214 + );
215 + }
216 +
217 + // Once Price alignment is chosen the item spans its row and the price fills
218 + // the space after the title/divider so text-align can position it. A % on
219 + // the title row needs the same; mirrors get_item_width_css() in styling.js.
220 + public static function get_item_width_css( $attributes, $device = '' ) {
221 + if ( ! empty( $attributes['priceAlignmentCustom'] ) ) {
222 + return $device ? [] : [ 'width' => '100%' ];
223 + }
224 + if ( self::is_percent_title_row( $attributes, $device ) ) {
225 + return [ 'width' => '100%' ];
226 + }
227 + return $device && self::has_percent_title_row( $attributes ) ? [ 'width' => 'fit-content' ] : [];
228 + }
229 +
230 + public static function get_price_row_css( $attributes ) {
231 + return ! empty( $attributes['priceAlignmentCustom'] ) ? [ 'flex-grow' => '1' ] : [];
232 + }
233 +
234 + /**
235 + * placeDivider / placePrice: a legacy string or a responsive array
236 + * ( value, valueTablet, valueMobile, … ). Mirrors placement.js.
237 + */
238 + public static function get_placement( $placement, $device = '' ) {
239 + $placement = is_array( $placement ) ? $placement : [ 'value' => (string) $placement ];
240 + $target = 'Desktop' === $device ? '' : (string) $device;
241 + foreach ( array_merge( [ $target ], Helper::get_responsive_ancestors( $target ) ) as $suffix ) {
242 + $value = isset( $placement[ 'value' . $suffix ] ) ? $placement[ 'value' . $suffix ] : '';
243 + if ( Helper::has_responsive_value( $value ) ) {
244 + return $value;
245 + }
246 + }
247 + return '';
248 + }
249 +
250 + public static function get_used_placements( $placement ) {
251 + if ( ! is_array( $placement ) ) {
252 + return Helper::has_responsive_value( $placement ) ? [ $placement ] : [];
253 + }
254 + $used = [];
255 + foreach ( $placement as $key => $value ) {
256 + if ( 0 === strpos( $key, 'value' ) && is_string( $value ) && Helper::has_responsive_value( $value ) ) {
257 + $used[] = $value;
258 + }
259 + }
260 + return array_values( array_unique( $used ) );
261 + }
262 +
263 + // The placement is a block attribute and this name lands in a selector of
264 + // an inline <style>, which esc_css_value() does not cover; keep it a class.
265 + public static function get_slot_class_name( $kind, $placement ) {
266 + return 'ablocks-price-menu-' . $kind . '-slot--' . sanitize_html_class( preg_replace( '/\s+/', '-', $placement ) );
267 + }
268 +
269 + public static function get_slot_css( $placement, $slot, $device = '' ) {
270 + if ( count( self::get_used_placements( $placement ) ) < 2 ) {
271 + return [];
272 + }
273 + return [ 'display' => self::get_placement( $placement, $device ) === $slot ? 'block' : 'none' ];
274 + }
275 +
276 + public function get_title_text_css( $attributes, $device = '' ) {
277 + $typographyValueGlobal = ! empty( $attributes['titleTypographyGlobal'] ) ? $attributes['titleTypographyGlobal'] : array();
278 + return array_merge(
279 + [ 'color' => Color::get_css( isset( $attributes['titleColor'] ) ? $attributes['titleColor'] : '' ) ],
280 + isset( $attributes['titleTypography'] ) ? Typography::get_css( $attributes['titleTypography'], '', $device, $typographyValueGlobal ) : [],
281 + isset( $attributes['titleTextStroke'] ) ? TextStroke::get_css( $attributes['titleTextStroke'], '', $device ) : [],
282 + isset( $attributes['titleTextShadow'] ) ? TextShadow::get_css( $attributes['titleTextShadow'], '', $device ) : [],
283 + isset( $attributes['titleAlignment'] ) ? Alignment::get_css( $attributes['titleAlignment'], 'text-align', $device ) : [],
284 + );
285 + }
286 + public function get_description_text_css( $attributes, $device = '' ) {
287 + $typographyValueGlobal = ! empty( $attributes['descriptionTypographyGlobal'] ) ? $attributes['descriptionTypographyGlobal'] : array();
288 +
289 + return array_merge(
290 + [ 'color' => Color::get_css( isset( $attributes['descriptionColor'] ) ? $attributes['descriptionColor'] : '' ) ],
291 + isset( $attributes['descriptionTypography'] ) ? Typography::get_css( $attributes['descriptionTypography'], '', $device, $typographyValueGlobal ) : [],
292 + isset( $attributes['descriptionTextStroke'] ) ? TextStroke::get_css( $attributes['descriptionTextStroke'], '', $device ) : [],
293 + isset( $attributes['descriptionTextShadow'] ) ? TextShadow::get_css( $attributes['descriptionTextShadow'], '', $device ) : [],
294 + isset( $attributes['descriptionAlignment'] ) ? Alignment::get_css( $attributes['descriptionAlignment'], 'text-align', $device ) : [],
295 + );
296 + }
297 + public function get_divider_css( $attributes, $device = '' ) {
298 + $css = [];
299 +
300 + if ( ! empty( $attributes['color'] ) ) {
301 + $css['--ablocks-divider-pattern-color'] = Color::get_css(
302 + isset( $attributes['color'] ) ? $attributes['color'] : '#000000');
303 +
304 + }
305 +
306 + $moreRangeCSS = [];
307 + if ( isset( $attributes['dividerType'] ) && $attributes['dividerType'] === 'mask-style' && isset( $attributes['size'] ) && ! empty( $attributes['size'] ) ) {
308 + $moreRangeCSS = Range::get_css([
309 + 'attributeValue' => $attributes['size'],
310 + 'attribute_object_key' => 'value',
311 + 'isResponsive' => false,
312 + 'defaultValue' => null,
313 + 'hasUnit' => false,
314 + 'unitDefaultValue' => 'px',
315 + 'property' => '--ablocks-divider-pattern-height',
316 + ]);
317 + } elseif ( isset( $attributes['weight'] ) && ! empty( $attributes['weight'] ) ) {
318 + $moreRangeCSS = Range::get_css([
319 + 'attributeValue' => $attributes['weight'],
320 + 'attribute_object_key' => 'value',
321 + 'isResponsive' => false,
322 + 'defaultValue' => null,
323 + 'hasUnit' => false,
324 + 'unitDefaultValue' => 'px',
325 + 'property' => '--ablocks-divider-pattern-weight',
326 + ]);
327 + }//end if
328 +
329 + if ( ! empty( $attributes['dividerPatternUrl'] ) ) {
330 + if ( $attributes['dividerType'] === 'mask-style' ) {
331 + $css['--ablocks-divider-pattern-url'] = 'url(' . $attributes['dividerPatternUrl'] . ')';
332 + } else {
333 + $css['--ablocks-divider-pattern-style'] = $attributes['dividerPatternUrl'];
334 + }
335 + }
336 +
337 + return array_merge(
338 + $css,
339 + $moreRangeCSS,
340 + );
341 + }
342 + public function get_price_text_css( $attributes, $device = '' ) {
343 + $typographyValueGlobal = ! empty( $attributes['priceTypographyGlobal'] ) ? $attributes['priceTypographyGlobal'] : array();
344 + return array_merge(
345 + [ 'color' => Color::get_css( isset( $attributes['priceColor'] ) ? $attributes['priceColor'] : '' ) ],
346 + isset( $attributes['priceTypography'] ) ? Typography::get_css( $attributes['priceTypography'], '', $device, $typographyValueGlobal ) : [],
347 + isset( $attributes['priceTextStroke'] ) ? TextStroke::get_css( $attributes['priceTextStroke'], '', $device ) : [],
348 + isset( $attributes['priceTextShadow'] ) ? TextShadow::get_css( $attributes['priceTextShadow'], '', $device ) : [],
349 + isset( $attributes['priceAlignment'] ) ? Alignment::get_css( $attributes['priceAlignment'], 'text-align', $device ) : [],
350 + );
351 + }
352 +}