2025-12-01: Live Site Sync - User Profiles & MailChimp Integration¶
Session Overview¶
Two-part session (morning + afternoon) focusing on syncing live site with dev configuration, fixing user profile issues, and implementing MailChimp integration.
Part 1: Morning - User Profile Sync & Configuration Import¶
Issues Addressed¶
- Configuration import errors due to missing dependencies
- Module mismatches between dev and live
- User profile field visibility and access issues
- Conditional field validation problems
Configuration Import Fix¶
Problem: Configuration import failed due to missing field dependency
core.entity_view_display.user.user.default is afhankelijk van field.field.user.user.field_nieuwsbrief
Solution: Import field dependencies along with display configuration
mkdir -p /tmp/import-user
cp /tmp/dev-config/field.storage.user.field_nieuwsbrief.yml /tmp/import-user/
cp /tmp/dev-config/field.field.user.user.field_nieuwsbrief.yml /tmp/import-user/
cp /tmp/dev-config/core.entity_view_display.user.user.default.yml /tmp/import-user/
ldrush cim --partial --source=/tmp/import-user -y
Result: Successfully imported 3 configuration objects (2 create, 1 update)
Module Synchronization¶
Missing Modules on Live¶
Identified 16 modules present on dev but missing on live: - commerce_invoice, commerce_mollie, commerce_shipping - ctools_entity_mask - eca_commerce, eca_development - entity_print, entity_print_views - field_permissions - mailer_transport, symfony_mailer - physical - vg_invoice_styling - webform_attachment, webform_entity_print, webform_entity_print_attachment
Installation Process¶
-
Installed via Composer:
Result: 22 packages installed including dependencies -
Copied custom module:
-
Resolved config conflict:
-
Enabled all modules:
Result: 154 translations added, 241 updated, 319 configuration objects updated
Commerce Mollie Version Update¶
Critical Fix: Updated to dev version with duplicate invoice fix
Problem: Live had commerce_mollie 1.12.0, dev had 1.x-dev (commit cff6bc6) with race condition fix
Context from notes (20251121): - Issue: Duplicate invoices created (pending + paid) due to Mollie webhook + return URL race - Fix: commerce_mollie 1.x-dev commit cff6bc6 resolves the race condition
Solution:
Result: Upgraded to dev-1.x cff6bc6 matching dev environment
User Profile Access Issue¶
Problem¶
User 51 unable to access /user/51/openbaar/add
- Error: "U heeft geen toegangsrechten voor deze pagina"
- Profile page showed: "Je hebt nog geen openbaar profiel. Maak je profiel aan."
- User existed but had no openbaar profile
Investigation¶
- Verified user 51 exists (Willem Kaandorp)
- Checked permissions: authenticated users have "create openbaar profile" permission
- Verified profile type: multiple=false (correct - one profile per user)
- No existing openbaar profile found in database
Solution¶
Created profile programmatically to resolve edge case:
ldrush php:eval "
\$profile = \Drupal\profile\Entity\Profile::create([
'type' => 'openbaar',
'uid' => 51
]);
\$profile->save();
echo 'Profile ID: ' . \$profile->id();
"
Result: Profile 97 created for user 51, now accessible at /user/51/openbaar
Part 2: Afternoon - Conditional Fields & MailChimp Integration¶
Conditional Fields Configuration¶
Problem¶
Conditional fields on openbaar profile not working correctly: 1. field_beroep_anders worked (visible only when beroep = "anders") 2. field_student_instelling remained required even when hidden (validation error) 3. Fields sometimes stayed visible when they should hide
Root Causes¶
- Circular dependencies: field_beroep had dependencies on itself
- Required field: field_student_instelling was marked required at field level
- Missing fields: Conditional fields were hidden in form display
Solutions¶
Step 1: Re-add hidden fields to form display
ldrush php:eval "
\$display = \Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('profile.openbaar.default');
\$display->setComponent('field_beroep_anders', [
'type' => 'string_textfield',
'weight' => 5,
'region' => 'content',
'settings' => ['size' => 60, 'placeholder' => ''],
]);
\$display->setComponent('field_student_instelling', [
'type' => 'string_textfield',
'weight' => 6,
'region' => 'content',
'settings' => ['size' => 60, 'placeholder' => ''],
]);
\$display->save();
"
Step 2: Configure conditional fields via UI
At /admin/structure/conditional-fields/profile/openbaar:
- field_beroep -> field_beroep_anders (trigger: "anders")
- field_beroep -> field_student_instelling (trigger: "student")
- Both with "Reset target to default when dependency not triggered" enabled
Step 3: Remove circular dependencies
ldrush php:eval "
\$display = \Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('profile.openbaar.default');
\$component = \$display->getComponent('field_beroep');
if (isset(\$component['third_party_settings']['conditional_fields'])) {
unset(\$component['third_party_settings']['conditional_fields']);
\$display->setComponent('field_beroep', \$component);
\$display->save();
}
"
Step 4: Remove required constraint
Via UI at /admin/config/people/profile-types/manage/openbaar/fields
- Unchecked "Required field" for field_student_instelling
Final Configuration¶
field_beroep: required, always visible (controller field)
field_beroep_anders: required flag present but overridden by conditional fields with reset
field_student_instelling: not required, conditionally visible
How it works: - field_beroep_anders can stay "required" because reset target empties it when hidden - field_student_instelling must NOT be required at field level - Reset target ensures hidden fields are emptied on submit, bypassing validation
MailChimp Integration¶
Problem¶
Newsletter subscription failed with error:
Root cause: vg_mailchimp_subscribe module used old MailChimp 2.x API
- Service mailchimp.lists no longer exists in MailChimp 3.x
- Module was calling $mailchimp_lists->subscribe() method
Investigation¶
Current MailChimp 3.x services:
API structure:
- Service: mailchimp.api (ApiService class)
- Client: Retrieved via $api->getApiObject() (returns MailchimpApiUser)
- Method: $client->request($endpoint, $params, $method)
Solution: Update Module for MailChimp 3.x¶
Backup:
cp web/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.module \
web/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.module.backup
Changes made via automated script:
Old code:
$mailchimp_lists = \Drupal::service('mailchimp.lists');
$result = $mailchimp_lists->subscribe(
$list_id, $email, $merge_vars, [], TRUE
);
New code:
$mailchimp_api = \Drupal::service('mailchimp.api');
$mc_client = $mailchimp_api->getApiObject();
$subscriber_hash = md5(strtolower($email));
$params = [
'email_address' => $email,
'status' => 'pending', // double opt-in
'merge_fields' => [
'FNAME' => $merge_vars['FNAME'] ?? '',
'LNAME' => $merge_vars['LNAME'] ?? '',
'MMERGE3' => $merge_vars['MMERGE3'] ?? '',
],
];
try {
$result = $mc_client->request(
"lists/$list_id/members/$subscriber_hash",
$params,
'PUT'
);
} catch (\Exception $e) {
$result = FALSE;
}
Unsubscribe updated similarly:
$subscriber_hash = md5(strtolower($email));
$params = ['status' => 'unsubscribed'];
$result = $mc_client->request(
"lists/$list_id/members/$subscriber_hash",
$params,
'PATCH'
);
API Endpoints Used:
- Subscribe/Update: PUT lists/{list_id}/members/{subscriber_hash}
- Unsubscribe: PATCH lists/{list_id}/members/{subscriber_hash}
- Subscriber hash: md5(strtolower($email))
MailChimp Configuration UI¶
Problem¶
List ID was hardcoded in module: $list_id = '0dc076aa56';
- No easy way to switch between test and production lists
- Required code changes to update
Solution: Add Settings Form¶
Created files:
1. src/Form/SettingsForm.php - Configuration form with dropdown
2. vg_mailchimp_subscribe.routing.yml - Route to /admin/config/services/vg-mailchimp-subscribe
3. vg_mailchimp_subscribe.links.menu.yml - Admin menu link
Features:
- Dropdown populated from MailChimp API via $mailchimpApi->getAudiences()
- Shows list names with IDs: "Voedingsgeneeskunde platform (abc123xyz)"
- Fallback to textfield if API fails
- Stores selection in config: vg_mailchimp_subscribe.settings.list_id
Module updated to use config:
Type hint fixes applied:
- Removed ApiServiceInterface type hint (interface doesn't exist in 3.x)
- Changed array access to object property: $list_data['name'] to $list_data->name
Configuration path: /admin/config/services/vg-mailchimp-subscribe
Technical Details¶
Field Configuration¶
Profile openbaar fields:
field_weergavenaam: string, required
field_beroep: list_string, required, allowed values:
- therapeut, dietist, leefstijlcoach, arts
- onderzoeker, student, anders
field_beroep_anders: string (conditional: beroep=anders)
field_student_instelling: string (conditional: beroep=student)
field_bio: text_long
field_locatie: string
field_website_praktijk: link (cardinality 2)
field_telefoon: telephone, required
Conditional Fields Best Practice¶
Required + Reset Target: - Field can be marked "required" at field level - Reset target empties field when hidden - Empty + hidden = no validation - Result: "required when visible, skipped when hidden"
Without Reset Target: - Field must NOT be required at field level - Conditional fields only controls visibility - Validation always runs regardless of visibility
MailChimp Module Structure¶
vg_mailchimp_subscribe/
├── vg_mailchimp_subscribe.info.yml
├── vg_mailchimp_subscribe.module
├── vg_mailchimp_subscribe.routing.yml
├── vg_mailchimp_subscribe.links.menu.yml
└── src/
└── Form/
└── SettingsForm.php
Hooks implemented:
- vg_mailchimp_subscribe_user_insert() - Subscribe on registration
- vg_mailchimp_subscribe_user_update() - Handle newsletter toggle changes
Data flow: 1. User enables field_nieuwsbrief checkbox 2. Hook fires on user save 3. Loads openbaar profile to get field_beroep 4. Prepares merge fields (FNAME, LNAME, MMERGE3=beroep) 5. Calls MailChimp API via request() method 6. Logs success/failure to watchdog
Configuration Export Status¶
Live Site Configuration¶
All critical configs synced: - User entity view display with field_nieuwsbrief - Profile type openbaar with all fields - Field storage and field configs - Conditional fields dependencies - MailChimp settings
Module Parity¶
Dev and Live now have matching modules: - Commerce: invoice, mollie (1.x-dev), shipping - Entity Print suite - Field permissions - Symfony Mailer - All custom modules (vg_commerce, vg_invoice_styling, vg_mailchimp_subscribe)
Testing Performed¶
Profile Access¶
- User 51 can now access
/user/51/openbaar - Profile edit form displays correctly
- All fields visible and functional
Conditional Fields¶
- field_beroep: always visible
- Select "Anders, namelijk": field_beroep_anders appears
- Select "Student": field_student_instelling appears
- Select other: both conditional fields hidden
- Form submits without validation errors for hidden fields
MailChimp Integration¶
- Newsletter toggle functional
- No more service error
- Subscriptions sent to configured list
- Logs show successful API calls
Known Issues & Considerations¶
Module Versions¶
- commerce_mollie on 1.x-dev (intentional - has critical fix)
- All other modules on stable releases
Custom Code¶
- vg_mailchimp_subscribe updated for MailChimp 3.x
- Backup exists: vg_mailchimp_subscribe.module.backup
- Module now configurable via UI instead of code changes
Future Maintenance¶
- Monitor MailChimp API for changes
- Watch for commerce_mollie stable release with fix
- Keep custom modules updated with Drupal core
Next Session Planning¶
Immediate Tasks¶
- Choose notification system for welcome messages
- Decision needed: Block Dismiss vs Message Stack
- See comparison table in session notes
Upcoming Work¶
- Implement chosen notification system
- Create welcome message for new users (authenticated role)
- QR-code ticket product implementation (dev)
- Commerce setup migration (dev to live)
Reference Documents¶
- Event tickets with QR: Plan in Notities folder
- MailChimp tags strategy: Discussed for event attendees
- Invoice generation: See 20251121-invoice-generation-fix.md
Commands Reference¶
Configuration Import¶
# Partial config import
ldrush cim --partial --source=/path/to/config -y
# Delete conflicting config
ldrush config:delete config.name -y
# Export current config
ldrush config:export --destination=/tmp/config -y
Module Management¶
# Install via Composer
composer require drupal/module_name
# Enable modules
ldrush en module_name -y
# Check module status
ldrush pml --status=enabled
Profile/Field Management¶
# List fields on entity type
ldrush field-info profile openbaar
# Check field required status
ldrush config:get field.field.profile.openbaar.field_name required
# Set field not required
ldrush config:set field.field.profile.openbaar.field_name required false -y
MailChimp¶
# Check available services
ldrush php:eval "print_r(\Drupal::getContainer()->getServiceIds());"
# Test MailChimp API
ldrush php:eval "\$api = \Drupal::service('mailchimp.api');
print_r(\$api->getAudiences());"
Files Modified/Created¶
Modified¶
web/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.module- Updated for MailChimp 3.x API
- Changed hardcoded list_id to config-based
Created¶
web/modules/custom/vg_mailchimp_subscribe/src/Form/SettingsForm.phpweb/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.routing.ymlweb/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.links.menu.ymlweb/modules/custom/vg_invoice_styling/(copied from dev)/tmp/import-user/(temporary config import directory)
Backup Created¶
web/modules/custom/vg_mailchimp_subscribe/vg_mailchimp_subscribe.module.backup
Success Metrics¶
- Configuration import: 100% success rate after dependency resolution
- Module parity: 16/16 missing modules installed and enabled
- User profile access: Resolved for user 51, applicable to all users
- Conditional fields: Working correctly for both conditional fields
- MailChimp integration: Fully functional with configurable list selection
- No custom code fuik: Used standard modules where possible, documented all custom changes