| @@ -3,9 +3,8 @@ | ||
| 3 | 3 | namespace FluentCart\App\Services\Renderer; |
| 4 | 4 | |
| 5 | 5 | use FluentCart\Api\StoreSettings; |
| 6 | 6 | use FluentCart\Framework\Support\Arr; |
| 7 | -use FluentCart\App\Vite; | |
| 8 | 7 | use FluentCart\App\Helpers\Helper; |
| 9 | 8 | use FluentCart\App\Helpers\CartCheckoutHelper; |
| 10 | 9 | use FluentCart\App\Models\Product; |
| 11 | 10 | |
| @@ -142,11 +141,10 @@ | ||
| 142 | 141 | { |
| 143 | 142 | $image = Arr::get($this->currentCartItem, 'featured_media'); |
| 144 | 143 | $title = Arr::get($this->currentCartItem, 'title', __('Product Image', 'fluent-cart')); |
| 145 | 144 | |
| 146 | - if (!$image) { | |
| 147 | - $image = Vite::getAssetUrl('images/placeholder.svg'); | |
| 148 | - } | |
| 145 | + // Also maps the old generic icon a pre-existing cart row may still store. | |
| 146 | + $image = Helper::productImageOrPlaceholder($image); | |
| 149 | 147 | |
| 150 | 148 | ?> |
| 151 | 149 | |
| 152 | 150 | <div class="fct-cart-item-image"> |
| @@ -162,8 +160,18 @@ | ||
| 162 | 160 | |
| 163 | 161 | <?php |
| 164 | 162 | } |
| 165 | 163 | |
| 164 | + protected function getEventInfo() | |
| 165 | + { | |
| 166 | + return [ | |
| 167 | + 'item' => $this->currentCartItem, | |
| 168 | + 'cart' => null, | |
| 169 | + 'product' => $this->product, | |
| 170 | + 'variant' => null, | |
| 171 | + ]; | |
| 172 | + } | |
| 173 | + | |
| 166 | 174 | public function renderDetails() |
| 167 | 175 | { |
| 168 | 176 | ?> |
| 169 | 177 | |
| @@ -173,8 +181,9 @@ | ||
| 173 | 181 | $this->renderTitles(); |
| 174 | 182 | $this->renderItemPrice(); |
| 175 | 183 | $this->renderQuantity(); |
| 176 | 184 | (new CartItemRenderer($this->currentCartItem))->renderChildVariants(); |
| 185 | + do_action('fluent_cart/cart/line_item/line_meta', $this->getEventInfo()); | |
| 177 | 186 | ?> |
| 178 | 187 | |
| 179 | 188 | </div> |
| 180 | 189 | |
| @@ -185,9 +194,11 @@ | ||
| 185 | 194 | |
| 186 | 195 | public function renderTitles() |
| 187 | 196 | { |
| 188 | 197 | $postTitle = Arr::get($this->currentCartItem, 'post_title', ''); |
| 189 | - $variationTitle = Arr::get($this->currentCartItem, 'title', ''); | |
| 198 | + // The Cart model already resolves & appends variation_display_title on | |
| 199 | + // every cart item (Cart::getCartDataAttribute), so just read it. | |
| 200 | + $variationTitle = (string) Arr::get($this->currentCartItem, 'variation_display_title', Arr::get($this->currentCartItem, 'title', '')); | |
| 190 | 201 | $variationType = Arr::get($this->currentCartItem, 'variation_type', 'simple'); |
| 191 | 202 | |
| 192 | 203 | $aria_label = sprintf( |
| 193 | 204 | /* translators: 1: Post or product title */ |
| @@ -217,9 +228,13 @@ | ||
| 217 | 228 | } |
| 218 | 229 | |
| 219 | 230 | public function renderItemPrice() |
| 220 | 231 | { |
| 221 | - $price = Helper::toDecimal(Arr::get($this->currentCartItem, 'unit_price', 0)); | |
| 232 | + $price = Helper::toDecimal(Arr::get( | |
| 233 | + $this->currentCartItem, | |
| 234 | + 'line_meta.original_unit_price', | |
| 235 | + Arr::get($this->currentCartItem, 'unit_price', 0) | |
| 236 | + )); | |
| 222 | 237 | $quantity = Arr::get($this->currentCartItem, 'quantity', 1); |
| 223 | 238 | |
| 224 | 239 | ?> |
| 225 | 240 | <div class="fct-cart-item-price <?php echo $quantity <= 1 ? 'item-price-hidden' : '' ?>"> |
| @@ -310,9 +325,14 @@ | ||
| 310 | 325 | |
| 311 | 326 | public function renderItemTotal() |
| 312 | 327 | { |
| 313 | 328 | $quantity = Arr::get($this->currentCartItem, 'quantity', 0); |
| 314 | - $totalPrice = Arr::get($this->currentCartItem, 'unit_price', 0) * $quantity; | |
| 329 | + $displayUnitPrice = Arr::get( | |
| 330 | + $this->currentCartItem, | |
| 331 | + 'line_meta.original_unit_price', | |
| 332 | + Arr::get($this->currentCartItem, 'unit_price', 0) | |
| 333 | + ); | |
| 334 | + $totalPrice = $displayUnitPrice * $quantity; | |
| 315 | 335 | |
| 316 | 336 | if (Arr::get($this->currentCartItem, 'other_info.payment_type', 'onetime') == 'subscription') { |
| 317 | 337 | if (Arr::get($this->currentCartItem, 'other_info.manage_setup_fee') == 'yes') { |
| 318 | 338 | $signupFee = Arr::get($this->currentCartItem, 'other_info.signup_fee', 0); |
| @@ -347,10 +367,29 @@ | ||
| 347 | 367 | } |
| 348 | 368 | |
| 349 | 369 | public function renderTotal() |
| 350 | 370 | { |
| 351 | - | |
| 352 | - $subtotal = CartCheckoutHelper::make()->getItemsAmountSubtotal(true, true); | |
| 371 | + $cartItems = CartCheckoutHelper::make()->getItems(); | |
| 372 | + $grossTotal = 0; | |
| 373 | + foreach ($cartItems as $item) { | |
| 374 | + $paymentType = Arr::get($item, 'other_info.payment_type', ''); | |
| 375 | + $qty = max(1, (int) Arr::get($item, 'quantity', 1)); | |
| 376 | + $displayUnitPrice = (int) Arr::get( | |
| 377 | + $item, | |
| 378 | + 'line_meta.original_unit_price', | |
| 379 | + Arr::get($item, 'unit_price', 0) | |
| 380 | + ); | |
| 381 | + if ($paymentType === 'subscription') { | |
| 382 | + if ((int) Arr::get($item, 'other_info.trial_days', 0) > 0) { | |
| 383 | + $grossTotal += (int) Arr::get($item, 'other_info.signup_fee', 0); | |
| 384 | + } else { | |
| 385 | + $grossTotal += $displayUnitPrice * $qty + (int) Arr::get($item, 'other_info.signup_fee', 0); | |
| 386 | + } | |
| 387 | + } else { | |
| 388 | + $grossTotal += $displayUnitPrice * $qty; | |
| 389 | + } | |
| 390 | + } | |
| 391 | + $subtotal = Helper::toDecimal($grossTotal); | |
| 353 | 392 | $aria_label = sprintf( |
| 354 | 393 | /* translators: 1: Total price */ |
| 355 | 394 | __('Total cart price: %1$s', 'fluent-cart'), |
| 356 | 395 | esc_attr($subtotal) |
| @@ -362,9 +401,17 @@ | ||
| 362 | 401 | class="fct-cart-total-wrapper" |
| 363 | 402 | role="region" |
| 364 | 403 | aria-label="<?php esc_attr_e('Cart Total', 'fluent-cart'); ?>" |
| 365 | 404 | > |
| 366 | - <span><?php echo esc_html__('Total', 'fluent-cart'); ?>:</span> | |
| 405 | + <span><?php | |
| 406 | + /** | |
| 407 | + * Filters the cart total label. Lets a caller relabel it without | |
| 408 | + * reimplementing this markup; the default renders exactly as before. | |
| 409 | + * | |
| 410 | + * @param string $label | |
| 411 | + */ | |
| 412 | + echo esc_html(apply_filters('fluent_cart/cart/total_label', __('Total', 'fluent-cart'))); | |
| 413 | + ?></span> | |
| 367 | 414 | <span |
| 368 | 415 | data-fluent-cart-cart-total-price |
| 369 | 416 | aria-live="polite" |
| 370 | 417 | aria-label="<?php echo esc_attr($aria_label); ?>" |
| @@ -407,13 +454,21 @@ | ||
| 407 | 454 | public function renderCheckoutButton() |
| 408 | 455 | { |
| 409 | 456 | ?> |
| 410 | 457 | |
| 411 | - <a class="checkout-button" | |
| 458 | + <a class="checkout-button fct-primary-btn" | |
| 412 | 459 | href="<?php echo esc_attr($this->storeSettings->getCheckoutPage()); ?>" |
| 413 | 460 | role="button" |
| 414 | 461 | aria-label="<?php esc_attr_e('Go to checkout page', 'fluent-cart'); ?>"> |
| 415 | - <?php esc_html_e('Go to Checkout', 'fluent-cart'); ?> | |
| 462 | + <?php | |
| 463 | + /** | |
| 464 | + * Filters the cart checkout button text. Lets a caller relabel it | |
| 465 | + * without reimplementing this markup; the default is unchanged. | |
| 466 | + * | |
| 467 | + * @param string $text | |
| 468 | + */ | |
| 469 | + echo esc_html(apply_filters('fluent_cart/cart/checkout_button_text', __('Go to Checkout', 'fluent-cart'))); | |
| 470 | + ?> | |
| 416 | 471 | </a> |
| 417 | 472 | |
| 418 | 473 | <?php |
| 419 | 474 | |