Skip to content

Commit 4e6c361

Browse files
authored
v3 API patch 2.2.0 (#287)
* v3 API patch 2.2.0
1 parent b083e96 commit 4e6c361

18 files changed

+673
-168
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
Test/log
33
vendor
44

5-
.idea
5+
.idea
6+
/composer.phar

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
### [Unreleased]
88

9+
### [2.2.0-patch] - 2024-01-31
10+
11+
#### Changed
12+
- Updates 2.2.0 release to utilize Klaviyo's v3 APIs. V1/V2 APIs will be retired on June 30, 2024.
13+
914
### [2.2.0] - 2021-05-17
1015

1116
#### Fixes
@@ -60,7 +65,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6065
- CSP now uses report-only mode
6166

6267

63-
[Unreleased]: https://github.com/klaviyo/magento2-klaviyo/compare/2.1.1...HEAD
68+
[Unreleased]: https://github.com/klaviyo/magento2-klaviyo/compare/2.2.0-patch...HEAD
69+
[2.2.0-patch]: https://github.com/klaviyo/magento2-klaviyo/compare/2.2.0...2.2.0-patch
70+
[2.2.0]: https://github.com/klaviyo/magento2-klaviyo/compare/2.1.0...2.2.0
6471
[2.1.1]: https://github.com/klaviyo/magento2-klaviyo/compare/2.1.0...2.1.1
6572
[2.1.0]: https://github.com/klaviyo/magento2-klaviyo/compare/2.0.0...2.1.0
6673
[2.0.0]: https://github.com/klaviyo/magento2-klaviyo/compare/1.2.4...2.0.0

Helper/Data.php

Lines changed: 54 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
<?php
22
namespace Klaviyo\Reclaim\Helper;
33

4+
use Klaviyo\Reclaim\KlaviyoV3Sdk\KlaviyoV3Api;
45
use \Klaviyo\Reclaim\Helper\ScopeSetting;
56
use \Magento\Framework\App\Helper\Context;
67
use \Klaviyo\Reclaim\Helper\Logger;
78

89
class Data extends \Magento\Framework\App\Helper\AbstractHelper
910
{
10-
const USER_AGENT = 'Klaviyo/1.0';
11-
const KLAVIYO_HOST = 'https://a.klaviyo.com/';
12-
const LIST_V2_API = 'api/v2/list/';
13-
1411
/**
1512
* Klaviyo logger helper
1613
* @var \Klaviyo\Reclaim\Helper\Logger $klaviyoLogger
@@ -34,42 +31,32 @@ public function __construct(
3431
}
3532

3633
public function getKlaviyoLists($api_key=null){
37-
if (!$api_key) $api_key = $this->_klaviyoScopeSetting->getPrivateApiKey();
38-
39-
$ch = curl_init();
40-
curl_setopt($ch, CURLOPT_URL, 'https://a.klaviyo.com/api/v2/lists?api_key=' . $api_key);
41-
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
42-
43-
44-
$output = json_decode(curl_exec($ch));
45-
$statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
46-
curl_close($ch);
47-
48-
if ($statusCode !== 200) {
49-
if ($statusCode === 403) {
50-
$reason = 'The Private Klaviyo API Key you have set is invalid.';
51-
} elseif ($statusCode === 401) {
52-
$reason = 'The Private Klaviyo API key you have set is no longer valid.';
53-
} else {
54-
$reason = 'Unable to verify Klaviyo Private API Key.';
34+
if (!$api_key) {
35+
$api_key = $this->_klaviyoScopeSetting->getPrivateApiKey();
36+
}
37+
$api = new KlaviyoV3Api($this->_klaviyoScopeSetting->getPublicApiKey(), $api_key, $this->_klaviyoScopeSetting);
38+
$lists = array();
39+
$success = true;
40+
$error = null;
41+
try {
42+
$lists_response = $api->getLists();
43+
foreach ($lists_response as $list) {
44+
$lists[] = array(
45+
'id' => $list['id'],
46+
'name' => $list['attributes']['name']
47+
);
5548
}
56-
57-
$result = [
58-
'success' => false,
59-
'reason' => $reason
60-
];
61-
} else {
62-
usort($output, function($a, $b) {
63-
return strtolower($a->list_name) > strtolower($b->list_name) ? 1 : -1;
64-
});
65-
66-
$result = [
67-
'success' => true,
68-
'lists' => $output
69-
];
49+
} catch (\Exception $e) {
50+
$this->_klaviyoLogger->log(sprintf('Unable to fetch lists: %s', $e->getMessage()));
51+
$error = $e->getCode();
52+
$success = false;
7053
}
7154

72-
return $result;
55+
return [
56+
'success' => $success,
57+
'lists' => $lists,
58+
'error' => $error
59+
];
7360
}
7461

7562
/**
@@ -79,30 +66,41 @@ public function getKlaviyoLists($api_key=null){
7966
* @param string $source
8067
* @return bool|string
8168
*/
82-
public function subscribeEmailToKlaviyoList($email, $firstName = null, $lastName = null, $source = null)
69+
public function subscribeEmailToKlaviyoList($email)
8370
{
71+
$api = new KlaviyoV3Api($this->_klaviyoScopeSetting->getPublicApiKey(), $this->_klaviyoScopeSetting->getPrivateApiKey(), $this->_klaviyoScopeSetting);
8472
$listId = $this->_klaviyoScopeSetting->getNewsletter();
8573
$optInSetting = $this->_klaviyoScopeSetting->getOptInSetting();
8674

87-
$properties = [];
88-
$properties['email'] = $email;
89-
if ($firstName) $properties['$first_name'] = $firstName;
90-
if ($lastName) $properties['$last_name'] = $lastName;
91-
if ($source) $properties['$source'] = $source;
92-
if ($optInSetting == ScopeSetting::API_SUBSCRIBE) $properties['$consent'] = ['email'];
93-
94-
$propertiesVal = ['profiles' => $properties];
95-
96-
$path = self::LIST_V2_API . $listId . $optInSetting;
75+
$profileAttributes = [];
76+
$profileAttributes['email'] = $email;
9777

9878
try {
99-
$response = $this->sendApiRequest($path, $propertiesVal, 'POST');
79+
if ($optInSetting == ScopeSetting::API_SUBSCRIBE) {
80+
// Subscribe profile using the profile creation endpoint for lists
81+
$consent_profile_object = array(
82+
'type' => 'profile',
83+
'attributes' => array_merge($profileAttributes, array('subscriptions' => array(
84+
'email' => [
85+
'MARKETING'
86+
]
87+
)))
88+
);
89+
$api->subscribeMembersToList($listId, array($consent_profile_object));
90+
} else {
91+
// Search for profile by email using the api/profiles endpoint
92+
$existing_profile = $api->searchProfileByEmail($email);
93+
if (!$existing_profile) {
94+
$new_profile = $api->createProfile($profileAttributes);
95+
$profile_id = $new_profile["profile_id"];
96+
} else {
97+
$profile_id = $existing_profile["profile_id"];
98+
}
99+
$api->addProfileToList($listId, $profile_id);
100+
}
100101
} catch (\Exception $e) {
101-
$this->_klaviyoLogger->log(sprintf('Unable to subscribe %s to list %s: %s', $email, $listId, $e));
102-
$response = false;
102+
$this->_klaviyoLogger->log(sprintf('Unable to subscribe %s to list %s: %s', $email, $listId, $e->getMessage()));
103103
}
104-
105-
return $response;
106104
}
107105

108106
/**
@@ -111,94 +109,16 @@ public function subscribeEmailToKlaviyoList($email, $firstName = null, $lastName
111109
*/
112110
public function unsubscribeEmailFromKlaviyoList($email)
113111
{
112+
$api = new KlaviyoV3Api($this->_klaviyoScopeSetting->getPublicApiKey(), $this->_klaviyoScopeSetting->getPrivateApiKey(), $this->_klaviyoScopeSetting);
114113
$listId = $this->_klaviyoScopeSetting->getNewsletter();
115114

116-
$path = self::LIST_V2_API . $listId . ScopeSetting::API_SUBSCRIBE;
117-
$fields = [
118-
'emails' => [(string)$email],
119-
];
120-
121115
try {
122-
$response = $this->sendApiRequest($path, $fields, 'DELETE');
116+
$response = $api->unsubscribeEmailFromKlaviyoList($email, $listId);
123117
} catch (\Exception $e) {
124-
$this->_klaviyoLogger->log(sprintf('Unable to unsubscribe %s from list %s: %s', $email, $listId, $e));
118+
$this->_klaviyoLogger->log(sprintf('Unable to unsubscribe %s from list %s: %s', $email, $listId, $e->getMessage()));
125119
$response = false;
126120
}
127121

128122
return $response;
129123
}
130-
131-
public function klaviyoTrackEvent($event, $customer_properties=array(), $properties=array(), $timestamp=NULL)
132-
{
133-
if ((!array_key_exists('$email', $customer_properties) || empty($customer_properties['$email']))
134-
&& (!array_key_exists('$id', $customer_properties) || empty($customer_properties['$id']))) {
135-
136-
return 'You must identify a user by email or ID.';
137-
}
138-
$params = array(
139-
'token' => $this->_klaviyoScopeSetting->getPublicApiKey(),
140-
'event' => $event,
141-
'properties' => $properties,
142-
'customer_properties' => $customer_properties
143-
);
144-
145-
if (!is_null($timestamp)) {
146-
$params['time'] = $timestamp;
147-
}
148-
$encoded_params = $this->build_params($params);
149-
return $this->make_request('api/track', $encoded_params);
150-
151-
}
152-
protected function build_params($params) {
153-
return 'data=' . urlencode(base64_encode(json_encode($params)));
154-
}
155-
156-
protected function make_request($path, $params) {
157-
$url = self::KLAVIYO_HOST . $path . '?' . $params;
158-
$response = file_get_contents($url);
159-
return $response == '1';
160-
}
161-
162-
/**
163-
* @param string $path
164-
* @param array $params
165-
* @param string $method
166-
* @return mixed[]
167-
* @throws \Exception
168-
*/
169-
private function sendApiRequest(string $path, array $params, string $method = null)
170-
{
171-
$url = self::KLAVIYO_HOST . $path;
172-
173-
//Add API Key to params
174-
$params['api_key'] = $this->_klaviyoScopeSetting->getPrivateApiKey();
175-
176-
$curl = curl_init();
177-
$encodedParams = json_encode($params);
178-
179-
curl_setopt_array($curl, [
180-
CURLOPT_URL => $url,
181-
CURLOPT_RETURNTRANSFER => true,
182-
CURLOPT_CUSTOMREQUEST => (!empty($method)) ? $method : 'POST',
183-
CURLOPT_POSTFIELDS => $encodedParams,
184-
CURLOPT_USERAGENT => self::USER_AGENT,
185-
CURLOPT_HTTPHEADER => [
186-
'Content-Type: application/json',
187-
'Content-Length: ' . strlen($encodedParams)
188-
],
189-
]);
190-
191-
// Submit the request
192-
$response = curl_exec($curl);
193-
$err = curl_errno($curl);
194-
195-
if ($err) {
196-
throw new \Exception(curl_error($curl));
197-
}
198-
199-
// Close cURL session handle
200-
curl_close($curl);
201-
202-
return $response;
203-
}
204124
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Klaviyo\Reclaim\KlaviyoV3Sdk\Exception;
4+
5+
class KlaviyoApiException extends KlaviyoException
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Klaviyo\Reclaim\KlaviyoV3Sdk\Exception;
4+
5+
class KlaviyoAuthenticationException extends KlaviyoApiException
6+
{
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Klaviyo\Reclaim\KlaviyoV3Sdk\Exception;
4+
5+
use Exception;
6+
7+
class KlaviyoException extends Exception
8+
{
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Klaviyo\Reclaim\KlaviyoV3Sdk\Exception;
4+
5+
class KlaviyoRateLimitException extends KlaviyoApiException
6+
{
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Klaviyo\Reclaim\KlaviyoV3Sdk\Exception;
4+
5+
class KlaviyoResourceNotFoundException extends KlaviyoApiException
6+
{
7+
}

KlaviyoV3Sdk/Exception/index.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
4+
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
5+
header('Cache-Control: no-store, no-cache, must-revalidate');
6+
header('Cache-Control: post-check=0, pre-check=0', false);
7+
header('Pragma: no-cache');
8+
header('Location: ../');

0 commit comments

Comments
 (0)