lindemannrock / craft-campaign-manager
Campaign management with SMS, email, and WhatsApp invitations
Installs: 18
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Type:craft-plugin
pkg:composer/lindemannrock/craft-campaign-manager
Requires
- php: ^8.2
- craftcms/cms: ^5.0.0
- giggsey/libphonenumber-for-php: ^8.13
- lindemannrock/craft-logging-library: ^5.0
- lindemannrock/craft-plugin-base: ^5.0
- lindemannrock/craft-sms-manager: ^5.0
- verbb/formie: ^3.0
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
README
Campaign management for surveys with SMS and email invitations for Craft CMS 5.x.
License
This is a commercial plugin licensed under the Craft License. It will be available on the Craft Plugin Store soon. See LICENSE.md for details.
⚠️ Pre-Release
This plugin is in active development and not yet available on the Craft Plugin Store. Features and APIs may change before the initial public release.
Features
- Campaign Management: Create and manage survey campaigns linked to Formie forms
- Multi-site support with site-specific recipients
- Campaign types for organization
- Configurable invitation delay and expiry periods
- Recipient Management:
- Import recipients from CSV files
- Add individual recipients manually
- Track invitation status (sent, opened, submitted)
- Unique invitation codes per recipient
- Export recipients to CSV/JSON/Excel
- Multi-Channel Invitations:
- SMS invitations via SMS Manager
- Email invitations with customizable templates
- Bitly URL shortening for SMS links
- Queue-Based Processing:
- Batch processing for large recipient lists
- Background job execution
- Progress tracking
- Analytics Dashboard:
- Overview stats (recipients, invitations, opens, submissions)
- Daily activity charts
- Channel distribution (Email/SMS/Both)
- Engagement tracking over time
- Conversion funnel visualization
- Campaign performance comparison
- Export analytics to CSV/JSON/Excel
- Filter by campaign, site, and date range
- Survey Response Tracking:
- Link Formie submissions to recipients
- Track survey completion rates
- Invitation expiry handling
- View responses directly in campaign edit page
- User Permissions: Granular access control for campaigns, recipients, analytics, and settings
- Logging: Structured logging via Logging Library with configurable levels
Requirements
- Craft CMS 5.0 or greater
- PHP 8.2 or greater
- Formie 3.0 or greater
- SMS Manager 5.0 or greater (for SMS invitations)
- Logging Library 5.0 or greater (installed automatically)
- Plugin Base 5.0 or greater (installed automatically)
Installation
Via Composer (Development)
Until published on Packagist, install directly from the repository:
cd /path/to/project
composer config repositories.campaign-manager vcs https://github.com/LindemannRock/craft-campaign-manager
composer require lindemannrock/craft-campaign-manager:dev-main
./craft plugin/install campaign-manager
Via Composer (Production - Coming Soon)
Once published on Packagist:
cd /path/to/project
composer require lindemannrock/craft-campaign-manager
./craft plugin/install campaign-manager
Via Plugin Store (Future)
- Go to the Plugin Store in your Craft control panel
- Search for "Campaign Manager"
- Click "Install"
Configuration
Settings
Navigate to Campaign Manager → Settings in the control panel to configure:
General Settings:
- Plugin Name: Customize the display name in the control panel
- Campaign Section Handle: The section handle where campaigns are stored
Bitly Settings:
- Bitly API Key: API key for URL shortening (environment variable recommended)
Logging Settings:
- Log Level: debug, info, warning, error
Environment Variables
# .env
BITLY_API_KEY=your-bitly-api-key
Config File
Create a config/campaign-manager.php file to override default settings:
<?php return [ // Plugin Settings 'pluginName' => 'Campaign Manager', 'campaignSectionHandle' => 'campaigns', // Logging Settings 'logLevel' => 'error', // Multi-environment support 'dev' => [ 'logLevel' => 'debug', ], 'production' => [ 'logLevel' => 'error', ], ];
Setup
1. Create Campaign Section
Create a Craft section for campaigns with the following fields:
- Campaign Type (Dropdown): Type categorization
- Form (Formie Form): The survey form
- Invitation Delay Period (Text): ISO 8601 duration (e.g.,
P1Dfor 1 day) - Invitation Expiry Period (Text): ISO 8601 duration (e.g.,
P30Dfor 30 days) - SMS Invitation Message (Plain Text): SMS template with
{invitationUrl}and{customer_name}tokens - Email Invitation Subject (Plain Text): Email subject line
- Email Invitation Message (Rich Text): Email template with tokens
- Sender ID (Text): SMS sender ID handle
- Surveys Welcome (Rich Text): Message shown before survey
- Surveys Already Responded (Rich Text): Message for completed surveys
- Surveys Invitation Expired (Rich Text): Message for expired invitations
2. Configure Plugin Settings
- Navigate to Campaign Manager → Settings
- Set the Campaign Section Handle to match your section
- Configure Bitly API key if using SMS invitations
3. Create Survey Template
Create a template for the survey page (e.g., templates/survey.twig):
{% extends '_layouts/surveys.twig' %}
{% block content %}
{% set invitationCode = craft.app.request.getQueryParam('code') %}
{% if invitationCode %}
{% set recipient = campaignManager.recipients.getRecipientByInvitationCode(invitationCode) %}
{% set campaign = recipient.getCampaign() %}
{% if recipient.hasSubmission() %}
{{ campaign.surveysAlreadyResponded|raw }}
{% elseif recipient.invitationIsExpired() %}
{{ campaign.surveysInvitationExpired|raw }}
{% else %}
{{ campaign.surveysWelcome|raw }}
{{ craft.formie.renderForm(campaign.getForm()) }}
{% endif %}
{% else %}
<p>Invalid invitation code.</p>
{% endif %}
{% endblock %}
Usage
Managing Campaigns
- Navigate to Campaign Manager in the control panel
- Click New Campaign to create a campaign entry
- Configure the campaign settings and associated form
- Save the campaign
Adding Recipients
Single Recipient
- Navigate to the campaign's recipient list
- Click Add → New Recipient
- Enter recipient details (name, email, phone, site)
- Save
Import from CSV
- Navigate to the campaign's recipient list
- Click Add → Import from CSV
- Upload a CSV file with columns:
Name(required)Email(optional)Phone(optional)Site(optional: site handle likeen,aror site ID like1,2)
- Choose whether to send invitations after import
- Click Import
CSV Format Example:
Name,Email,Phone,Site John Doe,john@example.com,96512345678,en Ahmed Ali,ahmed@example.com,96598765432,ar
Running Campaigns
Single Campaign
- Navigate to the campaign's recipient list
- Click Run Campaign
- Invitations will be queued and sent in batches
All Campaigns
- Navigate to Campaign Manager → Campaigns
- Click Run All
- All campaigns will be processed
Viewing Analytics
- Navigate to Campaign Manager → Analytics
- Use filters to select campaign, site, and date range
- View metrics across four tabs:
- Overview: Key stats and campaign performance table
- Delivery: Daily activity and channel distribution
- Engagement: Open rates over time
- Conversion: Funnel visualization and breakdown
- Export data using the Export button
Viewing Responses
- Navigate to a campaign and click Edit
- Click the Responses tab
- View all recipients who submitted the form
- Click "View" to see full submission details in Formie
Exporting Recipients
- Navigate to the campaign's recipient list
- Click Export
- Choose format (CSV, JSON, or Excel)
- Download includes all recipient data and status
Template Variables
campaignManager.campaigns
{# Get all campaigns #} {% set campaigns = campaignManager.campaigns.find().all() %} {# Get campaign by ID #} {% set campaign = campaignManager.campaigns.find().id(123).one() %} {# Get campaigns for a site #} {% set campaigns = campaignManager.campaigns.find().site('en').all() %}
campaignManager.recipients
{# Get recipient by invitation code #} {% set recipient = campaignManager.recipients.getRecipientByInvitationCode(code) %} {# Mark recipient as opened #} {% do campaignManager.recipients.markAsOpened(recipient) %} {# Check recipient status #} {% if recipient.hasSubmission() %} {# Already submitted #} {% elseif recipient.invitationIsExpired() %} {# Invitation expired #} {% endif %} {# Get recipients with submissions for a campaign #} {% set respondents = campaignManager.recipients.getWithSubmissions(campaignId, siteId) %}
Console Commands
# Run all campaigns ./craft campaign-manager/campaigns/run-all # Run specific campaign ./craft campaign-manager/campaigns/run --campaign=123
Permissions
Campaign Permissions
- Manage campaigns
- View campaigns
- Create campaigns
- Edit campaigns
- Delete campaigns
- Run campaigns
Recipient Permissions
- Manage recipients
- View recipients
- Add recipients
- Import recipients
- Export recipients
- Delete recipients
Analytics Permissions
- View analytics
- Export analytics
Logs Permissions
- View logs
- Download logs
Settings Permissions
- Manage settings
Events
use lindemannrock\campaignmanager\services\RecipientsService; use lindemannrock\campaignmanager\events\RecipientEvent; use yii\base\Event; // Before sending invitation Event::on( RecipientsService::class, RecipientsService::EVENT_BEFORE_SEND_INVITATION, function(RecipientEvent $event) { // Access: $event->recipient, $event->campaign // Set $event->isValid = false to cancel } ); // After sending invitation Event::on( RecipientsService::class, RecipientsService::EVENT_AFTER_SEND_INVITATION, function(RecipientEvent $event) { // Access: $event->recipient, $event->success } );
Troubleshooting
Invitations Not Sending
- Check SMS Manager is configured: Ensure providers and sender IDs are set up
- Check Bitly API key: Required for SMS URL shortening
- Check queue is running:
./craft queue/run - Check logs: Campaign Manager → Logs
Survey Page Not Loading
- Verify invitation code: Check the URL has a valid
codeparameter - Check recipient exists: The invitation code must match a recipient record
- Check campaign has form: The campaign must have a Formie form assigned
CSV Import Failing
- Check CSV format: Must have
Namecolumn at minimum - Check encoding: Use UTF-8 encoding for special characters
- Check file size: Large files are processed in batches
Bitly URLs Not Working
- Verify API key: Check
BITLY_API_KEYenvironment variable - Check API limits: Bitly has rate limits on free plans
- Fallback: If Bitly fails, original URLs are used
Logging
Campaign Manager uses the LindemannRock Logging Library for system logging.
Log Levels
- Error: Critical errors only (default)
- Warning: Errors and warnings
- Info: General information
- Debug: Detailed debugging (requires devMode)
Log Files
- Location:
storage/logs/campaign-manager-YYYY-MM-DD.log - Retention: 30 days (automatic cleanup)
- Web Interface: View logs at Campaign Manager → Logs
Support
- Documentation: https://github.com/LindemannRock/craft-campaign-manager
- Issues: https://github.com/LindemannRock/craft-campaign-manager/issues
- Email: support@lindemannrock.com
License
This plugin is licensed under the Craft License. See LICENSE.md for details.
Developed by LindemannRock