Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public function init(): void
{
parent::init();

// Set the base template directory for the plugin
Craft::setAlias('@klaviyo-connect-plus', $this->getBasePath());

$this->setComponents([
'api' => \fostercommerce\klaviyoconnectplus\services\Api::class,
'track' => \fostercommerce\klaviyoconnectplus\services\Track::class,
Expand Down
46 changes: 37 additions & 9 deletions src/controllers/CartController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,59 @@ public function actionRestore(): Response
throw new HttpException(400, 'Cart is empty');
}

// Restore the cart using reflection (Commerce 5 workaround)
// Get current user
$currentUser = Craft::$app->getUser()->getIdentity();
$currentUserId = $currentUser ? $currentUser->id : null;

// Check if cart belongs to a user account
// If user is not logged in, or logged in as different user
if ($order->customerId && (! $currentUserId || $order->customerId !== $currentUserId)) {
// Show message page using CP template mode
$loginPath = Craft::$app->getConfig()->getGeneral()->getLoginPath();
$loginUrl = \craft\helpers\UrlHelper::url($loginPath, [
'return' => Craft::$app->getRequest()->getAbsoluteUrl(),
]);
$view = Craft::$app->getView();
$oldMode = $view->getTemplateMode();
$view->setTemplateMode(\craft\web\View::TEMPLATE_MODE_CP);
$html = $view->renderTemplate('klaviyo-connect-plus/login-required', [
'loginUrl' => $loginUrl,
'message' => Craft::t('klaviyo-connect-plus', 'This cart belongs to a user account. Please log in to view it.'),
]);
$view->setTemplateMode($oldMode);
return $this->asRaw($html);
}

// At this point, either:
// - Cart has no customer (guest cart), OR
// - Current user owns the cart

// Clear current cart
$cartsService = $commerce->getCarts();
$cartsService->forgetCart();

// Set session
$session = Craft::$app->getSession();
$session->set('commerce_cart', $order->number);

// Use reflection to set the cart
try {
$reflection = new \ReflectionClass($cartsService);
$cartProperty = $reflection->getProperty('_cart');
$cartProperty->setAccessible(true);
$cartProperty->setValue($cartsService, $order);

$session = Craft::$app->getSession();
$session->set('commerce_cart', $order->number);

$session->setNotice(Craft::t('klaviyo-connect-plus', 'Your cart has been restored.'));
} catch (\Exception $exception) {
Craft::error('Failed to restore cart: ' . $exception->getMessage(), 'klaviyo-connect-plus');
throw new HttpException(500, 'Failed to restore cart');
Craft::error('Reflection failed: ' . $exception->getMessage(), 'klaviyo-connect-plus');
}

$session->setNotice(Craft::t('klaviyo-connect-plus', 'Your cart has been restored.'));

/** @var Settings $settings */
$settings = Plugin::getInstance()->getSettings();
$cartUrl = $settings->cartUrl;

if ((string) $cartUrl === '') {
throw new HttpException(400, 'Cart URL is required. Configure it in Settings -> Klaviyo Connect Plus -> Cart URL');
throw new HttpException(400, 'Cart URL is required.');
}

return $this->redirect($cartUrl);
Expand Down
160 changes: 160 additions & 0 deletions src/templates/login-required.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Required</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #1a1d29 0%, #2d3748 50%, #3d5a80 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
position: relative;
overflow: hidden;
}
body::before {
content: '';
position: absolute;
width: 500px;
height: 500px;
background: radial-gradient(circle, rgba(197, 167, 119, 0.08) 0%, transparent 70%);
top: -250px;
right: -250px;
border-radius: 50%;
}
body::after {
content: '';
position: absolute;
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(197, 167, 119, 0.05) 0%, transparent 70%);
bottom: -300px;
left: -300px;
border-radius: 50%;
}
.container {
background: rgba(255, 255, 255, 0.98);
border-radius: 16px;
box-shadow: 0 25px 80px rgba(0, 0, 0, 0.4);
max-width: 500px;
width: 100%;
padding: 48px;
text-align: center;
position: relative;
z-index: 1;
backdrop-filter: blur(10px);
}
.icon {
width: 80px;
height: 80px;
background: linear-gradient(135deg, #c5a777 0%, #a88f65 100%);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 28px;
box-shadow: 0 8px 24px rgba(197, 167, 119, 0.3);
}
.icon svg {
width: 40px;
height: 40px;
color: white;
}
h1 {
font-size: 28px;
font-weight: 700;
color: #1a1d29;
margin-bottom: 16px;
letter-spacing: -0.5px;
}
p {
font-size: 17px;
color: #4a5568;
line-height: 1.7;
margin-bottom: 36px;
}
.button {
display: inline-block;
background: linear-gradient(135deg, #c5a777 0%, #a88f65 100%);
color: white;
text-decoration: none;
padding: 16px 40px;
border-radius: 10px;
font-weight: 600;
font-size: 17px;
transition: all 0.3s;
box-shadow: 0 4px 16px rgba(197, 167, 119, 0.3);
position: relative;
overflow: hidden;
}
.button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #d4b685 0%, #b69a73 100%);
opacity: 0;
transition: opacity 0.3s;
}
.button:hover::before {
opacity: 1;
}
.button span {
position: relative;
z-index: 1;
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(197, 167, 119, 0.4);
}
.badge {
display: inline-flex;
align-items: center;
gap: 8px;
background: #f0f4f8;
color: #4a5568;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
margin-top: 24px;
}
.badge svg {
width: 16px;
height: 16px;
color: #c5a777;
}
</style>
</head>
<body>
<div class="container">
<div class="icon">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z"></path>
</svg>
</div>
<h1>Login Required</h1>
<p>{{ message }}</p>
<a href="{{ loginUrl }}" class="button">
<span>Log In to Continue</span>
</a>
<div class="badge">
<svg fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
</svg>
Secure cart restoration
</div>
</div>
</body>
</html>