Download the PHP package instride/opendxp-campaigns without Composer
On this page you can find all versions of the php package instride/opendxp-campaigns. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download instride/opendxp-campaigns
More information about instride/opendxp-campaigns
Files in instride/opendxp-campaigns
Package opendxp-campaigns
Short Description OpenDXP bundle for campaign management, including newsletter and email marketing features.
License GPL-3.0-or-later
Homepage https://github.com/instride-ch/opendxp-campaigns
Informations about the package opendxp-campaigns
Newsletter subscriptions and segments live in OpenDXP and are kept in step with a mail provider: what a member is subscribed to, the merge fields behind it, and which segments they belong to. Everything a provider does sits behind a driver — Mailchimp is the one that ships, a second one needs no change above the driver layer. Changes travel both ways: out over Messenger when an object is saved, back in through the provider's webhook or a nightly pull.
Requirements
PHP 8.3, 8.4 or 8.5, and OpenDXP 1.3 with its admin bundle. The Mailchimp driver additionally needs
drewm/mailchimp-api, which is suggested rather than required so a project on another provider does
not carry it.
Installation
Register the bundle in config/bundles.php:
Then let it install what it needs — the subscription fieldcollection and, where they are missing, the class definitions described below:
bin/console opendxp:bundle:list shows whether it is enabled and installed.
Class definitions
The installer creates the NewsletterMember, NewsletterSegment and NewsletterSegmentGroup
class definitions only when no class of that name exists yet. It compares names, not contents,
so an existing class of the right name is left alone even when it does not satisfy the contracts —
and the bundle then reports itself installed while nothing works.
| Your project | What to do |
|---|---|
| No such classes | Nothing. The installer creates them. |
| Own classes, contracts satisfied | Point member_class and segments.*_class at them. |
| Own classes, contracts not satisfied | Implement the interface and use the matching trait, or rename them out of the way. |
Satisfying a contract is usually three lines:
NewsletterSubscriptionTrait expects a fieldcollection field newsletterSubscriptions allowing
CampaignNewsletterSubscription; NewsletterSegmentTrait and NewsletterSegmentGroupTrait cover
the segment side, the latter expecting a multiselect field lists fed by
NewsletterListOptionsProvider. The CampaignNewsletterSubscription fieldcollection is overwritten
on every install, so local changes to it are lost.
Configuration
Incoming events reach /webhooks/campaigns/mailchimp/<connector>, which has to be registered at
the provider and needs webhook_secret set. Without it nothing comes back except through a pull.
From your application
The bundle exposes one service, NewsletterManagerInterface. Inject it and speak in members and
lists; which provider is behind them, and what it calls things, is none of the caller's business.
Both write what the provider now holds back onto the member, so a later push knows it has nothing
to do. Passing a plain address instead of an object works too — then nothing is recorded, because
there is nothing to record it on. isSubscribed(), hasMember() and getMember() ask the provider
directly, and syncMemberToList() is what the push and the queue use for one member.
When a status arrives from the provider — through the webhook or a pull —
MemberSubscriptionStatusChangedEvent is dispatched with the member, the list, the previous and the
new status, and where it came from:
Commands
| Command | |
|---|---|
campaigns:newsletter:pull --list=<list> |
provider → OpenDXP |
campaigns:newsletter:push --list=<list> |
OpenDXP → provider; --member=<id\|email> for one, --dry-run, --async |
campaigns:newsletter:push --list=<list> --segments |
brings groups and segments in line and removes what only the provider holds |
campaigns:migrate:cmf-remote-ids |
see migrating from the CMF |
campaigns:migrate:interests |
adopts the provider's IDs for existing groups and the membership behind them |
Segments and members reach the provider on save, over Messenger. The --segments pass is the
recovery path for messages that never arrived; run it from cron. After a group was lost at the
provider, run it before the member push — recreating a group yields new provider IDs, and only
the member push writes the memberships again.
Before your first synchronisation
Coming from Pimcore's Customer Management Framework, three steps come first: pull the statuses, import the provider IDs, and bring the group membership back. Skipping one costs you a mass unsubscribe, a duplicate of every group, segment and template, or an audience that no longer knows who belongs to which group. → docs/migrating-from-cmf.md
Message queue
Every message the bundle dispatches is routed to its own opendxp_campaigns transport, so a
slow provider call cannot hold up OpenDXP's own queues. Run a consumer for it, otherwise
member and segment changes queue up and never reach the provider:
The transport is a plain Doctrine queue. To use RabbitMQ (or anything else) instead, point the same name at another DSN in the application — no change to the bundle:
Routing resolves through CampaignsMessageInterface, which all messages implement, so a single
entry redirects all of them at once:
License
instride AG, Sandgruebestrasse 4, 6210 Sursee, Switzerland
[email protected], instride.ch
Copyright © 2026 instride AG. All rights reserved.
For licensing details please visit LICENSE.md
All versions of opendxp-campaigns with dependencies
open-dxp/admin-bundle Version ^1.3
open-dxp/opendxp Version ^1.3