511 lines
12 KiB
PHP
511 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @author Tassos Marinos <info@tassos.gr>
|
|
* @link https://www.tassos.gr
|
|
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
|
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
|
*/
|
|
|
|
namespace NRFramework\Integrations;
|
|
|
|
use NRFramework\Functions;
|
|
|
|
// No direct access
|
|
defined('_JEXEC') or die;
|
|
|
|
class MailChimp extends Integration
|
|
{
|
|
/**
|
|
* MailChimp Endpoint URL
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $endpoint = 'https://<dc>.api.mailchimp.com/3.0';
|
|
|
|
/**
|
|
* Create a new instance
|
|
*
|
|
* @param array $options The service's required options
|
|
* @throws \Exception
|
|
*/
|
|
public function __construct($options)
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->setKey($options);
|
|
|
|
if (strpos($this->key, '-') === false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
list(, $data_center) = explode('-', $this->key);
|
|
$this->endpoint = str_replace('<dc>', $data_center, $this->endpoint);
|
|
|
|
$this->options->set('headers.Authorization', 'apikey ' . $this->key);
|
|
}
|
|
|
|
/**
|
|
* Subscribe user to MailChimp
|
|
*
|
|
* @param string $list_id The ID of the MailChimp list
|
|
* @param string $email The email address of the subscriber
|
|
* @param object $merge_fields The custom field that are associated with the subscriber where the keys are the merge tags.
|
|
* @param boolean $double_optin If true, the subscriber will be added with status "pending" and a confirmation email will be sent to the user.
|
|
* @param boolean $allow_update If true, the subscriber will be updated if it already exists. Otherwise, an error will be thrown.
|
|
* @param array $tags The tags that are associated with the subscriber.
|
|
* @param string $tags_replace Determines what changes to make to the subscriber's tags. Values: add_only, replace_all
|
|
* @param array $interests The interests that are associated with the subscriber.
|
|
* @param string $interests_replace Determines what changes to make to the subscriber's groups/interests. Values: add_only, replace_all
|
|
*
|
|
* @return void
|
|
*/
|
|
public function subscribeV2($list_id, $email, $merge_fields = null, $double_optin = true, $allow_update = true, $tags = null, $tags_replace = 'add_only', $interests = [], $interests_replace = 'add_only')
|
|
{
|
|
$data = [
|
|
'email_address' => $email,
|
|
'status' => $double_optin ? 'pending' : 'subscribed',
|
|
'merge_fields' => (object) $merge_fields,
|
|
'tags' => Functions::cleanArray($tags)
|
|
];
|
|
|
|
$member = $this->getMemberByEmail($list_id, $email);
|
|
|
|
// Prepare Interests
|
|
$interests = Functions::cleanArray($interests);
|
|
$interests = $interests ? array_fill_keys($interests, true) : [];
|
|
|
|
if ($member && isset($member['interests']) && $interests_replace == 'replace_all')
|
|
{
|
|
// Disable all existing groups
|
|
$memberInterests = array_fill_keys(array_keys($member['interests']), false);
|
|
|
|
// Merge new interests with existing interests
|
|
$interests = array_merge($memberInterests, $interests);
|
|
}
|
|
|
|
$data['interests'] = (object) $interests;
|
|
|
|
if (!$member)
|
|
{
|
|
// API Doc: https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
|
|
$this->post('lists/' . $list_id . '/members', $data);
|
|
return;
|
|
}
|
|
|
|
// Member exists
|
|
// Since member exists and we don't allow updating existing member, throw an error.
|
|
if (!$allow_update)
|
|
{
|
|
throw new \Exception('Member already exists');
|
|
}
|
|
|
|
// Skip double opt-in if the existing member is already confirmed
|
|
if (isset($member['status']) && $member['status'] == 'subscribed')
|
|
{
|
|
$data['status'] = $member['status'];
|
|
}
|
|
|
|
// Update existing member
|
|
// API Doc: https://mailchimp.com/developer/marketing/api/list-members/add-or-update-list-member
|
|
$this->put('lists/' . $list_id . '/members/' . $member['id'], $data);
|
|
|
|
// Remove existing member tags not included in the given Tags.
|
|
if ($member['tags'] && $tags_replace == 'replace_all')
|
|
{
|
|
$currentTags = array_map(function($item) { return $item['name']; }, $member['tags']);
|
|
|
|
if ($removeTags = array_diff($currentTags, $data['tags']))
|
|
{
|
|
$rTags = [];
|
|
|
|
foreach ($removeTags as $removeTag)
|
|
{
|
|
$rTags[] = [
|
|
'name' => $removeTag,
|
|
'status' => 'inactive'
|
|
];
|
|
}
|
|
|
|
// API Doc: https://mailchimp.com/developer/marketing/api/list-member-tags/add-or-remove-member-tags/
|
|
$this->post('lists/' . $list_id . '/members/' . $member['id'] . '/tags', ['tags' => $rTags]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Subscribe user to MailChimp
|
|
*
|
|
* API References:
|
|
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-put_lists_list_id_members_subscriber_hash
|
|
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
|
|
*
|
|
* @param string $email User's email address
|
|
* @param string $list The MailChimp list unique ID
|
|
* @param Object $merge_fields Merge Fields
|
|
* @param boolean $update_existing Update existing user
|
|
* @param boolean $double_optin Send MailChimp confirmation email?
|
|
*
|
|
* @deprecated Use subscribeV2()
|
|
*
|
|
* @return void
|
|
*/
|
|
public function subscribe($email, $list, $merge_fields = array(), $update_existing = true, $double_optin = false)
|
|
{
|
|
$data = array(
|
|
'email_address' => $email,
|
|
'status' => $double_optin ? 'pending' : 'subscribed'
|
|
);
|
|
|
|
// add support for tags
|
|
if ($tags = $this->getTags($merge_fields))
|
|
{
|
|
$data['tags'] = $tags;
|
|
}
|
|
|
|
if (is_array($merge_fields) && count($merge_fields))
|
|
{
|
|
foreach ($merge_fields as $merge_field_key => $merge_field_value)
|
|
{
|
|
$value = is_array($merge_field_value) ? implode(',', $merge_field_value) : (string) $merge_field_value;
|
|
$data['merge_fields'][$merge_field_key] = $value;
|
|
}
|
|
}
|
|
|
|
$interests = $this->validateInterestCategories($list, $merge_fields);
|
|
|
|
if (!empty($interests))
|
|
{
|
|
$data = array_merge($data, array('interests' => $interests));
|
|
}
|
|
|
|
if ($update_existing)
|
|
{
|
|
// Get subscriber information.
|
|
$subscriberHash = md5(strtolower($email));
|
|
$member = $this->get('lists/' . $list . '/members/' . $subscriberHash);
|
|
|
|
// Skip double opt-in if the subscriber exists and it's confirmed
|
|
if (isset($member['status']) && $member['status'] == 'subscribed')
|
|
{
|
|
$data['status'] = $member['status'];
|
|
}
|
|
|
|
$this->put('lists/' . $list . '/members/' . $subscriberHash, $data);
|
|
|
|
if ($tags)
|
|
{
|
|
$tags_ = [];
|
|
|
|
foreach ($tags as $tag)
|
|
{
|
|
$tags_[] = [
|
|
'name' => $tag,
|
|
'status' => 'active'
|
|
];
|
|
}
|
|
|
|
$currentTags = $this->getMemberTags($list, $subscriberHash);
|
|
|
|
if ($removeTags = array_diff($currentTags, $tags))
|
|
{
|
|
foreach ($removeTags as $removeTag)
|
|
{
|
|
$tags_[] = [
|
|
'name' => $removeTag,
|
|
'status' => 'inactive'
|
|
];
|
|
}
|
|
}
|
|
|
|
$this->post('lists/' . $list . '/members/' . $subscriberHash . '/tags', ['tags' => $tags_]);
|
|
}
|
|
|
|
} else
|
|
{
|
|
$this->post('lists/' . $list . '/members', $data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use subscribeV2()
|
|
*/
|
|
private function getMemberTags($list, $subscriberHash)
|
|
{
|
|
$tags = $this->get('lists/' . $list . '/members/' . $subscriberHash . '/tags');
|
|
|
|
$return = [];
|
|
|
|
if (isset($tags['tags']))
|
|
{
|
|
foreach ($tags['tags'] as $tag)
|
|
{
|
|
$return[] = $tag['name'];
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Find and return all unique tags
|
|
*
|
|
* @param array $merge_fields
|
|
*
|
|
* @deprecated use subscribeV2()
|
|
*
|
|
* @return array
|
|
*/
|
|
private function getTags($merge_fields)
|
|
{
|
|
$tags = [];
|
|
|
|
// ensure tags are added in the form
|
|
if (!isset($merge_fields['tags']))
|
|
{
|
|
return $tags;
|
|
}
|
|
|
|
$mergeFieldsTags = $merge_fields['tags'];
|
|
|
|
// make string array
|
|
if (is_string($mergeFieldsTags))
|
|
{
|
|
$tags = explode(',', $mergeFieldsTags);
|
|
}
|
|
|
|
// ensure we have array to manipulate
|
|
if (is_array($mergeFieldsTags) || is_object($mergeFieldsTags))
|
|
{
|
|
$tags = (array) $mergeFieldsTags;
|
|
}
|
|
|
|
// remove empty values, keep uniques and reset keys
|
|
$tags = array_filter($tags);
|
|
$tags = array_unique($tags);
|
|
$tags = array_values($tags);
|
|
$tags = array_map('trim', $tags);
|
|
|
|
return $tags;
|
|
}
|
|
|
|
/**
|
|
* Returns all available MailChimp lists
|
|
*
|
|
* https://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getLists()
|
|
{
|
|
$data = $this->get('/lists');
|
|
|
|
if (!$this->success())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!isset($data['lists']) || !is_array($data['lists']))
|
|
{
|
|
return;
|
|
}
|
|
|
|
$lists = [];
|
|
|
|
foreach ($data['lists'] as $key => $list)
|
|
{
|
|
$lists[] = array(
|
|
'id' => $list['id'],
|
|
'name' => $list['name']
|
|
);
|
|
}
|
|
|
|
return $lists;
|
|
}
|
|
|
|
/**
|
|
* Gets the Interest Categories from MailChimp
|
|
*
|
|
* @param string $listID The List ID
|
|
*
|
|
* @deprecated Use subscribeV2()
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getInterestCategories($listID)
|
|
{
|
|
if (!$listID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
$data = $this->get('/lists/' . $listID . '/interest-categories');
|
|
|
|
if (!$this->success())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isset($data['total_items']) && $data['total_items'] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
return $data['categories'];
|
|
}
|
|
|
|
/**
|
|
* Gets the values accepted for the particular Interest Category
|
|
*
|
|
* @param string $listID The List ID
|
|
* @param string $interestCategoryID The Interest Category ID
|
|
*
|
|
* @deprecated Use subscribeV2()
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getInterestCategoryValues($listID, $interestCategoryID)
|
|
{
|
|
if (!$interestCategoryID || !$listID)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$data = $this->get('/lists/' . $listID . '/interest-categories/' . $interestCategoryID . '/interests');
|
|
|
|
if (isset($data['total_items']) && $data['total_items'] == 0)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
return $data['interests'];
|
|
}
|
|
|
|
/**
|
|
* Filters the interests categories through the form fields
|
|
* and constructs the interests array for the subscribe method
|
|
*
|
|
* @param string $listID The List ID
|
|
* @param array $params The Form fields
|
|
*
|
|
* @deprecated Use subscribeV2()
|
|
*
|
|
* @return array
|
|
*/
|
|
public function validateInterestCategories($listID, $params)
|
|
{
|
|
if (!$params || !$listID)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$interestCategories = $this->getInterestCategories($listID);
|
|
|
|
if (!$interestCategories)
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$categories = array();
|
|
|
|
foreach ($interestCategories as $category)
|
|
{
|
|
if (array_key_exists($category['title'], $params))
|
|
{
|
|
$categories[] = array('id' => $category['id'], 'title' => $category['title']);
|
|
}
|
|
}
|
|
|
|
if (empty($categories))
|
|
{
|
|
return array();
|
|
}
|
|
|
|
$interests = array();
|
|
|
|
foreach ($categories as $category)
|
|
{
|
|
$data = $this->getInterestCategoryValues($listID, $category['id']);
|
|
|
|
if (isset($data['total_items']) && $data['total_items'] == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach ($data as $interest)
|
|
{
|
|
if (in_array($interest['name'], (array) $params[$category['title']]))
|
|
{
|
|
$interests[$interest['id']] = true;
|
|
}
|
|
else
|
|
{
|
|
$interests[$interest['id']] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $interests;
|
|
}
|
|
|
|
/**
|
|
* Find a subscriber in a list by email address
|
|
*
|
|
* @param string $list_id The MailChimp list ID
|
|
* @param string $email The email address
|
|
*
|
|
* @return mixed Object on success, false on failure
|
|
*/
|
|
public function getMemberByEmail($list_id, $email)
|
|
{
|
|
$subscriberHash = md5(strtolower($email));
|
|
$result = $this->get('lists/' . $list_id . '/members/' . $subscriberHash);
|
|
|
|
return $this->success() ? $result : false;
|
|
}
|
|
|
|
/**
|
|
* Get the last error returned by either the network transport, or by the API.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getLastError()
|
|
{
|
|
$body = $this->last_response->body;
|
|
|
|
if (isset($body['errors']))
|
|
{
|
|
$error = $body['errors'][0];
|
|
return $error['field'] . ': ' . $error['message'];
|
|
}
|
|
|
|
if (isset($body['detail']))
|
|
{
|
|
return $body['detail'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The get() method overridden so that it handles
|
|
* the default item paging of MailChimp which is 10
|
|
*
|
|
* @param string $method URL of the API request method
|
|
* @param array $args Assoc array of arguments (usually your data)
|
|
* @return array|false Assoc array of API response, decoded from JSON
|
|
*/
|
|
public function get($method, $args = array())
|
|
{
|
|
$data = $this->makeRequest('get', $method, $args);
|
|
|
|
if ($data && isset($data['total_items']) && (int) $data['total_items'] > 10)
|
|
{
|
|
$args['count'] = $data['total_items'];
|
|
return $this->makeRequest('get', $method, $args);
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
} |