PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.1
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Services / Renderer / CartItemRenderer.php

CartItemRenderer.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.5.1, at app/Services/Renderer/CartItemRenderer.php

375 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\Renderer;
4
5 use FluentCart\App\Helpers\AttributeHelper;
6 use FluentCart\App\Helpers\Helper;
7 use FluentCart\App\Models\Cart;
8 use FluentCart\Framework\Support\Arr;
9 use FluentCart\App\Vite;
10
11 class CartItemRenderer
12 {
13 protected $item = [];
14 protected $cart = null;
15
16 protected $product = null;
17
18 protected $variant = null;
19
20 public function __construct($item = [], ?Cart $cart = null)
21 {
22 $this->item = $item;
23 $this->cart = $cart;
24 }
25
26 protected function getEventInfo()
27 {
28 return [
29 'item' => $this->item,
30 'cart' => $this->cart,
31 'product' => $this->product,
32 'variant' => $this->variant,
33 ];
34 }
35
36 public function render()
37 {
38 $wrapperClassAttributes = [
39 'fct_line_item',
40 'fct_product_id_' . Arr::get($this->item, 'post_id', ''),
41 'fct_item_id_' . Arr::get($this->item, 'id', ''),
42 'fct_item_type_' . Arr::get($this->item, 'other_info.payment_type', ''),
43 ];
44
45 if (Arr::get($this->item, 'featured_media')) {
46 $wrapperClassAttributes[] = 'fct_has_image';
47 }
48
49 $promoPriceOriginal = Arr::get($this->item, 'other_info.promo_price_original', 0);
50 if ($promoPriceOriginal && $promoPriceOriginal > $this->item['unit_price']) {
51 $promoPriceOriginal = $promoPriceOriginal * Arr::get($this->item, 'quantity', 1);
52 } else {
53 $promoPriceOriginal = '';
54 }
55
56 $couponDiscount = (int) Arr::get($this->item, 'coupon_discount', 0);
57 $lineTotal = (int) Arr::get($this->item, 'line_total', 0);
58 $subtotal = (int) Arr::get($this->item, 'subtotal', 0);
59 $hasCouponDiscount = $couponDiscount > 0 && $lineTotal < $subtotal;
60 ?>
61 <div class="<?php $this->renderCssAtts($wrapperClassAttributes); ?>" role="listitem">
62 <div class="fct_line_item_body">
63 <div class="fct_line_item_info">
64 <?php $this->renderImage(); ?>
65 <div class="fct_item_content">
66 <?php $this->renderTitle(); ?>
67 <?php $this->renderChildVariants(); ?>
68 <?php do_action('fluent_cart/cart/line_item/line_meta', $this->getEventInfo()); ?>
69 </div>
70 </div><!-- .fct_line_item_info -->
71
72 <div class="fct_line_item_price" aria-label="<?php esc_attr_e('Price information', 'fluent-cart'); ?>">
73 <?php if($promoPriceOriginal) : ?>
74 <div style="text-decoration: line-through;" class="fct_line_item_total fct_promo_price" aria-label="<?php esc_attr_e('Original price', 'fluent-cart'); ?>">
75 <?php echo esc_html(Helper::toDecimal($promoPriceOriginal)); ?>
76 </div>
77 <?php endif; ?>
78 <div class="fct_item_price_wrapper">
79 <?php do_action('fluent_cart/cart/line_item/before_total', $this->getEventInfo()); ?>
80 <span class="fct_line_item_total<?php echo $hasCouponDiscount ? ' fct_coupon_original_price' : ''; ?>" aria-label="<?php esc_attr_e('Total price', 'fluent-cart'); ?>">
81 <?php echo esc_html(Helper::toDecimal($subtotal)); ?>
82 </span>
83 <?php if ($hasCouponDiscount) : ?>
84 <span class="fct_line_item_total fct_coupon_discounted_price" aria-label="<?php esc_attr_e('Discounted price', 'fluent-cart'); ?>">
85 <?php echo esc_html(Helper::toDecimal($lineTotal)); ?>
86 </span>
87 <?php endif; ?>
88 <?php do_action('fluent_cart/cart/line_item/after_total', $this->getEventInfo()); ?>
89 </div>
90 </div><!-- .fct_line_item_price -->
91 </div>
92 <div class="fct_line_item_footer">
93 <?php do_action('fluent_cart/cart/line_item/footer_start', $this->getEventInfo()); ?>
94
95 <?php $hasSetupFee = $this->maybeRenderSetupFeeInfo(); ?>
96 <?php if ($hasSetupFee) : ?>
97 <?php $this->renderSetupFeeInfo() ?>
98 <?php do_action('fluent_cart/cart/line_item/after_setup_fee_info', $this->getEventInfo()); ?>
99 <?php endif; ?>
100 <?php do_action('fluent_cart/cart/line_item/footer_end', $this->getEventInfo()); ?>
101 </div>
102 </div>
103 <?php
104 }
105
106 public function renderTitle()
107 {
108 $href = Arr::get($this->item, 'view_url', '');
109
110 $mainTitle = (string) Arr::get($this->item, 'post_title', '');
111
112 // Prefer the labeled attribute combination ("Color: Red | Size: XS")
113 // when the item carries an attribute snapshot; fall back to the raw
114 // variation title for custom/simple items.
115 $itemAttributes = (array) Arr::get($this->item, 'other_info.item_attributes', []);
116 $attributesText = $itemAttributes
117 ? AttributeHelper::getDisplayAttributesString($itemAttributes, $this->item, 'cart')
118 : '';
119 $subtitle = $attributesText !== '' ? $attributesText : (string) Arr::get($this->item, 'title', '');
120
121 $quantity = Arr::get($this->item, 'quantity', 1);
122
123 ?>
124 <div class="fct_item_title">
125 <?php do_action('fluent_cart/cart/line_item/before_main_title', $this->getEventInfo()); ?>
126 <?php if ($quantity > 1): ?>
127 <span class="fct_item_quantity" aria-label="<?php echo esc_attr(sprintf(
128 /* translators: %d: quantity */
129 __('Quantity %d', 'fluent-cart'), $quantity)); ?>">
130 <?php echo esc_attr($quantity); ?> <span aria-hidden="true">x</span>
131 </span>
132 <?php endif; ?>
133 <?php if ($href): ?>
134 <a
135 href="<?php echo esc_url($href); ?>"
136 aria-label="<?php echo esc_attr(sprintf(
137 /* translators: %s: product title */
138 __('View details for %s', 'fluent-cart'), $mainTitle)); ?>"
139 >
140 <?php echo wp_kses_post($mainTitle); ?>
141 </a>
142 <?php else: ?>
143 <?php echo wp_kses_post($mainTitle); ?>
144 <?php endif; ?>
145
146 <?php if ($mainTitle != $subtitle && $subtitle): ?>
147 <div class="fct_item_variant_title" aria-label="<?php esc_attr_e('Variant', 'fluent-cart'); ?>">
148 - <?php echo wp_kses_post($subtitle); ?>
149 </div>
150 <?php endif; ?>
151 <?php $this->maybeRenderPaymentTypeInfo(); ?>
152 <?php $this->maybeRenderPackageInfo(); ?>
153
154 <?php do_action('fluent_cart/cart/line_item/after_main_title', $this->getEventInfo()); ?>
155 </div>
156 <?php
157 }
158
159 public function renderImage()
160 {
161 $image = Arr::get($this->item, 'featured_media');
162 if (!$image) {
163 $image = Vite::getAssetUrl('images/placeholder.svg');
164 }
165 $href = Arr::get($this->item, 'view_url', '');
166 $altText = sprintf(
167 /* translators: %s: product title */
168 __('Image of %s', 'fluent-cart'), Arr::get($this->item, 'title', __('product', 'fluent-cart')));
169 ?>
170 <div class="fct_item_image">
171 <?php if ($href): ?>
172 <a href="<?php echo esc_url($href); ?>">
173 <img src="<?php echo esc_url($image); ?>"
174 alt="<?php echo esc_attr($altText); ?>"/>
175 </a>
176 <?php else: ?>
177 <img src="<?php echo esc_url($image); ?>"
178 alt="<?php echo esc_attr($altText); ?>"/>
179 <?php endif; ?>
180 </div>
181 <?php
182 }
183
184 protected function renderCssAtts($atts)
185 {
186 echo esc_attr(implode(' ', $atts));
187 }
188
189 protected function maybeRenderPaymentTypeInfo()
190 {
191 $otherInfo = Arr::get($this->item, 'other_info', []);
192 $paymentType = Arr::get($otherInfo, 'payment_type', '');
193 $itemPrice = Arr::get($this->item, 'unit_price', 0);
194
195 if (isset($this->item['recurring_discounts'])) {
196 $otherInfo['recurring_discounts'] = $this->item['recurring_discounts'];
197 }
198
199 if ($paymentType === 'subscription') {
200 $subscriptionInfo = Helper::generateSubscriptionInfo($otherInfo, $itemPrice);
201 $trialInfo = Helper::generateTrialInfo($otherInfo);
202 ?>
203 <div class="fct_item_payment_info">
204 <span class="sr-only"><?php esc_html_e('Payment information', 'fluent-cart'); ?></span>
205
206 <span> <?php echo wp_kses($subscriptionInfo, ['del' => true]); ?> </span>
207 <?php if ($trialInfo): ?>
208 <span class="trial-days"> <?php echo esc_html($trialInfo); ?> </span>
209 <?php endif; ?>
210 </div>
211 <?php
212 return;
213 }
214
215 $quantity = Arr::get($this->item, 'quantity', 1);
216
217 if ($quantity < 2) {
218 return;
219 }
220 ?>
221 <div class="fct_item_payment_info">
222 <?php
223 /* translators: %1$s: formatted unit price */
224 printf(esc_html__('%1$s each', 'fluent-cart'), esc_html(Helper::toDecimal($itemPrice)));
225 ?>
226 <?php do_action('fluent_cart/cart/line_item/unit_price_hint', $this->getEventInfo()); ?>
227 </div>
228 <?php
229 }
230
231 protected function maybeRenderSetupFeeInfo()
232 {
233 $paymentType = Arr::get($this->item, 'other_info.payment_type', '');
234 if ($paymentType !== 'subscription') {
235 return false;
236 }
237
238 $otherInfo = Arr::get($this->item, 'other_info', []);
239 $setupFeeInfo = Helper::generateSetupFeeInfo($otherInfo);
240 if (empty($setupFeeInfo)) {
241 return false;
242 }
243 return true;
244 }
245
246 protected function renderSetupFeeInfo()
247 {
248
249 $otherInfo = Arr::get($this->item, 'other_info', []);
250 $setupFeeInfo = Helper::generateSetupFeeInfo($otherInfo, true);
251 $setupFeeName = Arr::get($setupFeeInfo, 'signup_fee_name', '');
252 $setupFeePrice = Arr::get($setupFeeInfo, 'signup_fee_formatted', 0);
253
254 ?>
255 <div class="fct_item_payment_info">
256 <div class="fct_setup_fee_info">
257 <span class="setup-fee"><?php esc_html_e($setupFeeName) ?></span>
258 <span class="setup-fee-amount">
259 <?php esc_html_e($setupFeePrice) ?>
260 <?php do_action('fluent_cart/cart/line_item/setup_fee_price_info', $this->getEventInfo()); ?>
261 </span>
262 </div>
263 </div>
264 <?php
265
266 return true;
267 }
268
269 protected function maybeRenderPackageInfo()
270 {
271 if (Arr::get($this->item, 'fulfillment_type') !== 'physical') {
272 return;
273 }
274
275 $otherInfo = Arr::get($this->item, 'other_info', []);
276 if (!is_array($otherInfo)) {
277 return;
278 }
279
280 $packageSlug = Arr::get($otherInfo, 'package_slug', '');
281 $package = Helper::getPackageBySlug($packageSlug);
282 if (!$package) {
283 return;
284 }
285
286 $name = Arr::get($package, 'name', '');
287 $type = Arr::get($package, 'type', '');
288
289 $parts = [];
290 if ($name) {
291 $parts[] = $name;
292 }
293
294 $storeWeightUnit = Helper::shopConfig('weight_unit') ?: 'kg';
295 $productWeight = floatval(Arr::get($otherInfo, 'weight', 0));
296 $productWeightUnit = Arr::get($otherInfo, 'weight_unit', $storeWeightUnit);
297 $convertedProductWeight = Helper::convertWeight($productWeight, $productWeightUnit, $storeWeightUnit);
298 $packageWeight = floatval(Arr::get($package, 'weight', 0));
299 $packageWeightUnit = Arr::get($package, 'weight_unit', $storeWeightUnit);
300 $convertedPackageWeight = Helper::convertWeight($packageWeight, $packageWeightUnit, $storeWeightUnit);
301 $totalWeight = $convertedProductWeight + $convertedPackageWeight;
302
303 if ($totalWeight) {
304 $formatted = rtrim(rtrim(number_format($totalWeight, 2), '0'), '.');
305 $parts[] = $formatted . ' ' . $storeWeightUnit;
306 }
307
308 if (!$parts) {
309 return;
310 }
311
312 $icon = ShippingMethodsRender::getPackageTypeIcon($type ?: 'box');
313 ?>
314 <div class="fct_item_package_info">
315 <?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
316 <span><?php echo esc_html(implode(' · ', $parts)); ?></span>
317 </div>
318 <?php
319 }
320
321 public function renderChildVariants(){
322 $childVariants = Arr::get($this->item, 'child_variants', []);
323
324 if (empty($childVariants)) {
325 return;
326 }
327
328 $total = count($childVariants);
329
330 ?>
331 <div class="fct-bundle-products" data-fluent-cart-collapsibles>
332 <h4 class="fct-bundle-products-title">
333 <?php echo esc_html__('Bundle of', 'fluent-cart') . ':'; ?>
334 </h4>
335 <div class="fct-bundle-products-list">
336 <?php foreach (array_slice($childVariants, 0, 2) as $childVariant): ?>
337 <p>
338 <?php echo esc_html(Arr::get($childVariant, 'post_title')) . ' - ' . esc_html(Arr::get($childVariant, 'variation_title')); ?>
339 </p>
340 <?php endforeach; ?>
341
342 <?php if ($total > 2): ?>
343 <div class="fct-bundle-products-more">
344 <div class="fct-bundle-products-more-list">
345 <?php foreach (array_slice($childVariants, 2) as $childVariant): ?>
346 <p>
347 <?php echo esc_html(Arr::get($childVariant, 'post_title')) . ' - ' . esc_html(Arr::get($childVariant, 'variation_title')); ?>
348 </p>
349 <?php endforeach; ?>
350 </div>
351 </div>
352 <?php endif;?>
353 </div>
354
355 <?php if ($total > 2) : ?>
356 <a href="#" class="fct-see-more-btn" data-fluent-cart-collapsible-toggle>
357 <span class="see-more-text">
358 <?php echo esc_html__('See More', 'fluent-cart'); ?>
359 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="7" viewBox="0 0 12 7" fill="none">
360 <path d="M0.75 0.75L5.04289 5.04289C5.37623 5.37623 5.54289 5.54289 5.75 5.54289C5.95711 5.54289 6.12377 5.37623 6.45711 5.04289L10.75 0.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
361 </svg>
362 </span>
363 <span class="see-less-text">
364 <?php echo esc_html__('See Less', 'fluent-cart'); ?>
365 <svg xmlns="http://www.w3.org/2000/svg" width="12" height="7" viewBox="0 0 14 8" fill="none">
366 <path d="M0.75 6.54297L6.04289 1.25008C6.37623 0.916742 6.54289 0.750076 6.75 0.750076C6.95711 0.750076 7.12377 0.916742 7.45711 1.25008L12.75 6.54297" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
367 </svg>
368 </span>
369 </a>
370 <?php endif; ?>
371 </div>
372 <?php }
373
374 }
375