| 1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; ?> |
| 2 |
<?php |
| 3 |
/** |
| 4 |
* To the reviewer: their review is approved and on the product page. |
| 5 |
* |
| 6 |
* @var \FluentCart\App\Models\ProductReview $review |
| 7 |
* @var \FluentCart\App\Models\Product|object|null $product |
| 8 |
*/ |
| 9 |
$productTitle = $product && !empty($product->post_title) |
| 10 |
? (string) $product->post_title |
| 11 |
: __('the product', 'fluent-cart'); |
| 12 |
|
| 13 |
// The item the review names, when it does — resolved by the same helper every |
| 14 |
// other surface uses, so the email can never disagree with the product page |
| 15 |
// about what a review is about. On a copy: the helper sets item_label as an |
| 16 |
// attribute, and this template can render inside the request that approved |
| 17 |
// the review, on the very model the caller goes on to save() — a label left |
| 18 |
// on it would be written as a column the table does not have. |
| 19 |
$reviewWithItemLabel = clone $review; |
| 20 |
\FluentCart\App\Services\ProductReviewService::attachItemLabels([$reviewWithItemLabel]); |
| 21 |
$itemLabel = trim((string) $reviewWithItemLabel->getAttribute('item_label')); |
| 22 |
if ($itemLabel !== '') { |
| 23 |
/* translators: 1: product title, 2: item (variation) label */ |
| 24 |
$productTitle = sprintf(__('%1$s (%2$s)', 'fluent-cart'), $productTitle, $itemLabel); |
| 25 |
} |
| 26 |
|
| 27 |
$productId = $product && !empty($product->ID) ? (int) $product->ID : (int) $review->post_id; |
| 28 |
$productUrl = $productId ? get_permalink($productId) : ''; |
| 29 |
|
| 30 |
$reviewerName = trim((string) $review->reviewer_name); |
| 31 |
$rating = max(0, min(5, (int) $review->rating)); |
| 32 |
$isVerified = !empty($review->is_verified); |
| 33 |
?> |
| 34 |
|
| 35 |
<div class="space_bottom_30"> |
| 36 |
<p> |
| 37 |
<?php |
| 38 |
if ($reviewerName !== '') { |
| 39 |
/* translators: 1: the reviewer's name */ |
| 40 |
printf(esc_html__('Hello %1$s,', 'fluent-cart'), esc_html($reviewerName)); |
| 41 |
} else { |
| 42 |
esc_html_e('Hello,', 'fluent-cart'); |
| 43 |
} |
| 44 |
?> |
| 45 |
</p> |
| 46 |
<p> |
| 47 |
<?php |
| 48 |
printf( |
| 49 |
/* translators: 1: the product title */ |
| 50 |
esc_html__('Your review of %1$s has been approved and is now visible to shoppers on the product page.', 'fluent-cart'), |
| 51 |
'<strong>' . esc_html($productTitle) . '</strong>' |
| 52 |
); |
| 53 |
?> |
| 54 |
</p> |
| 55 |
</div> |
| 56 |
|
| 57 |
<?php // The review, quoted back — the card the storefront shows, in mail-safe markup. ?> |
| 58 |
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin-bottom:28px;background-color:#f8fafc;border:1px solid #e5e7eb;border-radius:8px;border-collapse:separate;"> |
| 59 |
<tbody> |
| 60 |
<tr> |
| 61 |
<td style="padding:24px 24px 20px;"> |
| 62 |
<?php if ($rating > 0) : ?> |
| 63 |
<?php // Filled and hollow glyphs, and the number in words: the |
| 64 |
// rating must read without colour — a screen reader, a |
| 65 |
// forced-colour display, or colour-blind eyes. ?> |
| 66 |
<p style="margin:0 0 12px;font-size:22px;line-height:1;letter-spacing:2px;"> |
| 67 |
<span style="color:<?php echo esc_attr(\FluentCart\App\Services\Renderer\ProductReviewRenderer::starColors()['filled']); ?>;"><?php echo str_repeat('★', $rating); ?></span><span style="color:<?php echo esc_attr(\FluentCart\App\Services\Renderer\ProductReviewRenderer::starColors()['empty']); ?>;"><?php echo str_repeat('☆', 5 - $rating); ?></span> |
| 68 |
<span style="font-size:13px;letter-spacing:0;color:#6b7280;vertical-align:middle;"> |
| 69 |
<?php |
| 70 |
printf( |
| 71 |
/* translators: 1: the rating given, out of five */ |
| 72 |
esc_html__('%1$d out of 5', 'fluent-cart'), |
| 73 |
$rating |
| 74 |
); |
| 75 |
?> |
| 76 |
</span> |
| 77 |
</p> |
| 78 |
<?php endif; ?> |
| 79 |
|
| 80 |
<?php if (!empty($review->title)) : ?> |
| 81 |
<p style="margin:0 0 10px;font-size:18px;font-weight:700;line-height:1.4;color:#111827;"><?php echo esc_html($review->title); ?></p> |
| 82 |
<?php endif; ?> |
| 83 |
|
| 84 |
<?php // Escaped first, then the reviewer's own line breaks put back — a |
| 85 |
// three-paragraph review must not arrive as one block. ?> |
| 86 |
<p style="margin:0;font-size:15px;line-height:1.7;color:#374151;"><?php echo nl2br(esc_html($review->content)); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by esc_html() before nl2br() ?></p> |
| 87 |
</td> |
| 88 |
</tr> |
| 89 |
<tr> |
| 90 |
<td style="padding:12px 24px;border-top:1px solid #e5e7eb;background-color:#f1f5f9;border-radius:0 0 8px 8px;font-size:13px;color:#6b7280;"> |
| 91 |
<?php |
| 92 |
if ($isVerified) { |
| 93 |
printf( |
| 94 |
/* translators: 1: the product title */ |
| 95 |
esc_html__('Verified purchase · %1$s', 'fluent-cart'), |
| 96 |
esc_html($productTitle) |
| 97 |
); |
| 98 |
} else { |
| 99 |
echo esc_html($productTitle); |
| 100 |
} |
| 101 |
?> |
| 102 |
</td> |
| 103 |
</tr> |
| 104 |
</tbody> |
| 105 |
</table> |
| 106 |
|
| 107 |
<?php if ($productUrl) : ?> |
| 108 |
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="margin-bottom:28px;"> |
| 109 |
<tbody> |
| 110 |
<tr> |
| 111 |
<td> |
| 112 |
<a href="<?php echo esc_url($productUrl); ?>" target="_blank" style="display:inline-block;background-color:#0f172a;color:#ffffff;padding:14px 28px;border-radius:8px;font-size:16px;font-weight:600;text-decoration:none;"> |
| 113 |
<?php esc_html_e('See your review', 'fluent-cart'); ?> → |
| 114 |
</a> |
| 115 |
</td> |
| 116 |
</tr> |
| 117 |
</tbody> |
| 118 |
</table> |
| 119 |
<?php endif; ?> |
| 120 |
|
| 121 |
<div class="space_bottom_30"> |
| 122 |
<p style="margin:0;font-size:15px;line-height:1.6;color:#9ca3af;"> |
| 123 |
<?php esc_html_e('Thank you for sharing your experience — reviews like yours help other shoppers decide with confidence.', 'fluent-cart'); ?> |
| 124 |
</p> |
| 125 |
</div> |
| 126 |
|