From 04dcaceed9c91ccffe07c83d8e078cb9b3679cfa Mon Sep 17 00:00:00 2001 From: Gaurang Sharma Date: Wed, 6 Aug 2025 01:19:13 +0530 Subject: [PATCH 1/2] Add MailerLite driver with configuration and README documentation --- README.md | 28 +++++ composer.json | 1 + config/newsletter.php | 2 + src/Drivers/MailerLiteDriver.php | 135 +++++++++++++++++++++++++ tests/Drivers/MailerLiteDriverTest.php | 11 ++ 5 files changed, 177 insertions(+) create mode 100644 src/Drivers/MailerLiteDriver.php create mode 100644 tests/Drivers/MailerLiteDriverTest.php diff --git a/README.md b/README.md index 19af4be..5b53396 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Currently this package support: - [Mailcoach](https://mailcoach.app) (built by us :-)) - [MailChimp](https://mailchimp.com) +- [MailerLite](https://mailerlite.com) ## Support us @@ -88,6 +89,8 @@ return [ * * When using the MailChimp driver, this should be a MailChimp list id. * http://kb.mailchimp.com/lists/managing-subscribers/find-your-list-id. + * + * When using MailerLite Driver, this should be a MailerLite group ID */ 'id' => env('NEWSLETTER_LIST_ID'), ], @@ -119,6 +122,20 @@ Next, you must provide values for the API key and `list.subscribers.id`. You'll The `endpoint` config value must be set to null. +### Using MailerLite + +To use MailerLite, install this extra package. + +```bash +composer require mailerlite/mailerlite-php +``` + +The `driver` key of the `newsletter` config file must be set to `Spatie\Newsletter\Drivers\MailerLiteDriver::class`. + +You need to provide the API key and the `group.id`. These can be found in your MailerLite Dashboard under Integrations > API. + +The `endpoint` config value must be set to null. + ## Usage After you've installed the package and filled in the values in the config-file working with this package will be a breeze. All the following examples use the facade. Don't forget to import it at the top of your file. @@ -154,6 +171,11 @@ For MailChimp you can pass merge variables as the second argument: Newsletter::subscribe('rincewind@discworld.com', ['FNAME'=>'Rince', 'LNAME'=>'Wind']); ``` +For MailerLite you can pass subscriber fields as the second argument: +```php +Newsletter::subscribe('rincewind@discworld.com', ['name'=>'Rince', 'last_name'=>'Wind']); +``` + You can subscribe someone to a specific list by passing a list name: ```php Newsletter::subscribe('rincewind@discworld.com', listName: 'subscribers'); @@ -186,6 +208,12 @@ Here's how to unsubscribe someone from a specific list: Newsletter::unsubscribe('rincewind@discworld.com', 'subscribers'); ``` +For MailerLite, if you provide the group ID as the second argument, the subscriber will be removed from that group. Otherwise, they will be marked as unsubscribed. + +```php +Newsletter::unsubscribe('rincewind@discworld.com', 'subscribers'); +``` + ### Deleting subscribers Deleting is not the same as unsubscribing. Unlike unsubscribing, deleting a member will result in the loss of all history (add/opt-in/edits) as well as removing them from the list. In most cases, you want to use `unsubscribe` instead of `delete`. diff --git a/composer.json b/composer.json index 429110e..0055653 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "require-dev": { "drewm/mailchimp-api": "^2.5", "guzzlehttp/guzzle": "^7.5|^7.2", + "mailerlite/mailerlite-php": "^1.0", "mockery/mockery": "^1.4", "orchestra/testbench": "^7.11|^8.0|^9.0|^10.0", "pestphp/pest": "^1.20|^2.0|^3.0", diff --git a/config/newsletter.php b/config/newsletter.php index a125d06..5ceabd5 100644 --- a/config/newsletter.php +++ b/config/newsletter.php @@ -40,6 +40,8 @@ * * When using the MailChimp driver, this should be a MailChimp list id. * http://kb.mailchimp.com/lists/managing-subscribers/find-your-list-id. + * + * When using MailerLite Driver, this should be a MailerLite group ID */ 'id' => env('NEWSLETTER_LIST_ID'), ], diff --git a/src/Drivers/MailerLiteDriver.php b/src/Drivers/MailerLiteDriver.php new file mode 100644 index 0000000..a6cf6fc --- /dev/null +++ b/src/Drivers/MailerLiteDriver.php @@ -0,0 +1,135 @@ +mailerLite = new MailerLite([ + 'api_key' => $arguments['api_key'] ?? '' + ]); + + $this->lists = $lists; + } + + public function getApi(): MailerLite + { + return $this->mailerLite; + } + + public function subscribe( + string $email, + array $properties = [], + string $listName = '', + array $options = [], + bool $unsubscribe = false + ): array|false { + $groupId = $this->lists->findByName($listName)->getId(); + + try { + $response = $this->mailerLite->subscribers->create([ + 'email' => $email, + 'groups' => [$groupId], + 'fields' => $properties, + 'status' => $unsubscribe ? 'unsubscribed' : null, + ]); + + return $response['body']['data'] ?? false; + } catch (\Exception $e) { + return false; + } + } + + public function subscribeOrUpdate( + string $email, + array $properties = [], + string $listName = '', + array $options = [] + ): array|false { + return $this->subscribe($email, $properties, $listName, $options); + } + + public function unsubscribe(string $email, string $listName = ''): array|false + { + if ($listName) { + $subscriber = $this->getMember($email, $listName); + + if ($subscriber) { + $groupId = $this->lists->findByName($listName)->getId(); + $this->mailerLite->groups->unAssignSubscriber($groupId, $subscriber['id']); + + return $this->getMember($email); + } + + return false; + } + + return $this->subscribe($email, listName: $listName, unsubscribe: true); + } + + public function delete(string $email, string $listName = ''): bool + { + $subscriber = $this->getMember($email, $listName); + + if ($subscriber) { + try { + $this->mailerLite->subscribers->delete($subscriber['id']); + return true; + } catch (\Exception $e) { + return false; + } + } + + return false; + } + + public function getMember(string $email, string $listName = ''): array|false + { + try { + $response = $this->mailerLite->subscribers->find($email); + + $groupId = $this->lists->findByName($listName)->getId(); + + return $this->matchGroup($response, $groupId); + } catch (\Exception $e) { + return false; + } + } + + public function hasMember(string $email, string $listName = ''): bool + { + return $this->getMember($email, $listName) !== false; + } + + public function isSubscribed(string $email, string $listName = ''): bool + { + $subscriber = $this->getMember($email, $listName); + + return $subscriber && ($subscriber['status'] ?? null) === 'active'; + } + + protected function matchGroup(array $subscriber, string|int $groupId): array|false + { + $groups = $subscriber['body']['data']['groups'] ?? []; + + $groupIds = array_column($groups, 'id'); + + if (in_array($groupId, $groupIds, true)) { + return $subscriber['body']['data']; + } + + return false; + } +} diff --git a/tests/Drivers/MailerLiteDriverTest.php b/tests/Drivers/MailerLiteDriverTest.php new file mode 100644 index 0000000..479d4ca --- /dev/null +++ b/tests/Drivers/MailerLiteDriverTest.php @@ -0,0 +1,11 @@ +set('newsletter.driver', MailerLiteDriver::class); + + expect(Newsletter::getApi())->toBeInstanceOf(MailerLite::class); +}); From 0f67947da0a3c1e6f732b63104c6ee6680c4d0b5 Mon Sep 17 00:00:00 2001 From: Gaurang Sharma Date: Wed, 6 Aug 2025 01:57:08 +0530 Subject: [PATCH 2/2] update composer.json --- composer.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 0055653..c9ade0d 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,12 @@ { "name": "spatie/laravel-newsletter", - "description": "Manage Mailcoach and MailChimp newsletters in Laravel", + "description": "Manage Mailcoach, MailChimp and MailerLite newsletters in Laravel", "keywords": [ "laravel", "newsletter", "mailcoach", - "mailchimp" + "mailchimp", + "mailerlite" ], "homepage": "https://github.com/spatie/laravel-newsletter", "license": "MIT", @@ -24,7 +25,8 @@ }, "suggest": { "spatie/mailcoach-sdk-php": "For working with Mailcoach", - "drewm/mailchimp-api": "For working with MailChimp" + "drewm/mailchimp-api": "For working with MailChimp", + "mailerlite/mailerlite-php": "For working with MailerLite" }, "require-dev": { "drewm/mailchimp-api": "^2.5",