PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.0
1.7.0 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 All 50 releases
fluent-cart / app / Services / Renderer / CartItemRenderer.php

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

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