klaviyoModule = $klaviyopsModule; } /** * Handle actionCustomerAccount hooks. Includes add and update. Subscribe customer * to the Klaviyo list selected in module settings if they subscribed, are active * and aren't deleted. * * @param array $params * @param string $event * @return void */ public function handleActionCustomerAccount(array $params, $event) { try { /** @var ContextService $contextService */ $contextService = $this->klaviyoModule->getService('klaviyops.prestashop_services.context'); /** @var CustomerService $customerService */ $customerService = $this->klaviyoModule->getService('klaviyops.prestashop_services.customer'); /** @var ProfileEventService $profileEventService */ $profileEventService = $this->klaviyoModule->getService('klaviyops.klaviyo_service.profile_event'); $api = new KlaviyoApiWrapper(); $customer = $this->getCustomerFromHookParams($params); if ($customer === null) { return; } $normalizedContext = $contextService->normalize(); // Current context $normalizedCustomer = $customerService->normalize( $customer, $normalizedContext ); if ( $customer->newsletter && $customer->active && !$customer->deleted && Configuration::get('KLAVIYO_PRIVATE_API') ) { try { $api->subscribeCustomer($customer->email); } catch (KlaviyoApiException $e) { /** @var LoggerService $logger */ $logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger'); $logger->log('error', self::ERROR_SUBSCRIBING_CUSTOMER . $customer->email); } } try { $profileEventService->track($event, $normalizedCustomer); } catch (KlaviyoApiException $e) { /** @var LoggerService $logger */ $logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger'); $logger->log('error', self::ERROR_UPDATING_CUSTOM_PROPERTIES . $customer->email); } } catch (Exception $e) { /** @var LoggerService $logger */ $logger = $this->klaviyoModule->getService('klaviyops.prestashop_services.logger'); if (Validate::isLoadedObject($customer)) { $logger->log('error', "An error occured in handleActionCustomerAccount for customer {$customer->email}"); } else { $logger->log('error', 'An error occured in handleActionCustomerAccount'); } } } /** * Handle actionNewsletterSubscriptionAfter hook used in the default PrestaShop * Newsletter Subscription module. * * @param array $params */ public function handleActionNewsletterSubscription(array $params) { if ( $params['action'] == static::NEWSLETTER_SUBSCRIPTION && !$params['error'] && Configuration::get('KLAVIYO_PRIVATE_API') ) { try { $api = new KlaviyoApiWrapper(); $api->subscribeCustomer($params['email']); } catch (KlaviyoApiException $e) { $logger = new LoggerService(); $logger->log('error', self::ERROR_SUBSCRIBING_CUSTOMER . $params['email']); } } } /** * Return new Webservice Resource definition to use specific management interface. * * @param array $resources * @return array[] */ public function handleAddWebserviceResources(array $resources) { return [ 'klaviyo' => [ 'description' => 'Klaviyo custom endpoints', 'specific_management' => true, ] ]; } /** * Add SMS Consent to customer address form * * @param array $params * @return array */ public function handleAdditionalCustomerAddressFields(array $params) { try { if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) { throw new KlaviyoApiException('Sync SMS Subscribers disabled'); } $trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER'); if (!$trigger) { throw new KlaviyoApiException('SMS Subscribe trigger not configured'); } $idLang = (int) Context::getContext()->language->id; $smsConsentLabel = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_CONSENT_LABEL', $idLang); $smsConsentDisclosure = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_CONSENT_DISCLOSURE_TEXT', $idLang); $label = "{$smsConsentLabel}
{$smsConsentDisclosure}"; $formField = new FormField(); $formField->setName('kl_sms_consent'); $formField->setType('checkbox'); $formField->setLabel($label); $formField->setRequired(false); return [$formField]; } catch (KlaviyoApiException $e) { return []; } } /** * Subscribe mobile to klaviyo list * * @param array $params * @return void */ public function handleActionSubmitCustomerAddressForm(array $params) { if ( !empty($params['address']) && is_object($params['address']) && Configuration::get('KLAVIYO_PRIVATE_API') && isset($params['address']->kl_sms_consent) && !empty($params['address']->kl_sms_consent) ) { $context = Context::getContext(); if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) { return; } $trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER'); if ($trigger === 'place_order') { // Save information in cookie to be triggered after payment (place order) $cookie = $context->cookie; $addressFields = [ $params['address']->phone ?? '', $params['address']->phone_mobile ?? '', ]; $addressToHash = implode('', array_map('strval', $addressFields)); $cookie->kl_sms_consent = Tools::hash($addressToHash); return; } // Trigger start checkout $mobile = $params['address']->phone_mobile ?? $params['address']->phone ?? ''; $isoCode = ''; if (!empty($params['address']->id_country)) { $country = new Country($params['address']->id_country); if (Validate::isLoadedObject($country)) { $isoCode = $country->iso_code; } } $attributes = ['mobile' => $mobile]; $customer = new Customer((int)$params['address']->id_customer); if (!Validate::isLoadedObject($customer)) { $customer = $context->customer; } if (Validate::isLoadedObject($customer)) { $attributes['email'] = $customer->email; } $this->sendSMSConsentRequestAPI($attributes, $isoCode); } } /** * Subscribe mobile to klaviyo list (place order trigger) * * @param array $params * @return void */ public function handleDisplayOrderConfirmation($params) { $cookie = Context::getContext()->cookie; if ( !empty($params['order']) && Validate::isLoadedObject($params['order']) && Configuration::get('KLAVIYO_PRIVATE_API') && isset($cookie->kl_sms_consent) && !empty($cookie->kl_sms_consent) ) { if (!$this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_IS_SYNCING_SMS_SUBSCRIBERS')) { return; } $trigger = $this->klaviyoModule->getConfigurationValueOrNull('KLAVIYO_SMS_SUBSCRIBE_TRIGGER'); if ($trigger !== 'place_order') { return; } // Check consent to invoice address $consentAddress = null; foreach ( [ $params['order']->id_address_invoice, $params['order']->id_address_delivery ] as $idAddress ) { $address = new Address((int)$idAddress); if (Validate::isLoadedObject($address)) { $addressFields = [ $address->phone ?? '', $address->phone_mobile ?? '', ]; $addressToHash = implode('', array_map('strval', $addressFields)); $addressHash = Tools::hash($addressToHash); if ($cookie->kl_sms_consent === $addressHash) { $consentAddress = $address; break; } } } // Get mobile on invoice address if (is_null($consentAddress)) { return; } $mobile = $address->phone_mobile ?? $address->phone ?? ''; $isoCode = ''; if (!empty($address->id_country)) { $country = new Country($address->id_country); if (Validate::isLoadedObject($country)) { $isoCode = $country->iso_code; } } $attributes = ['mobile' => $mobile]; $customer = new Customer((int)$params['order']->id_customer); if (Validate::isLoadedObject($customer)) { $attributes['email'] = $customer->email; } $this->sendSMSConsentRequestAPI($attributes, $isoCode); } } /** * Extract Customer object from hook params. * * @param array $hookParams * @return Customer|null */ private function getCustomerFromHookParams(array $hookParams) { if (isset($hookParams['customer']) && $hookParams['customer'] instanceof CustomerCore) { return $hookParams['customer']; } if (isset($hookParams['newCustomer']) && $hookParams['newCustomer'] instanceof CustomerCore) { return $hookParams['newCustomer']; } return null; } /** * Subscribe mobile to a list * * @param array $address * @param string $isoCode * @return void */ private function sendSMSConsentRequestAPI($address = [], $isoCode = '') { if (empty($address) || !is_array($address)) { return; } if (empty($address['mobile'])) { return; } try { $address['mobile'] = KlaviyoUtils::formatPhone($address['mobile'], $isoCode); $api = new KlaviyoApiWrapper(); $api->subscribeSMSCustomer($address); } catch (KlaviyoApiException $e) { $logger = new LoggerService(); $logger->log('error', self::ERROR_SUBSCRIBING_SMS_CUSTOMER . $address['mobile']); } } }