Skip to content

Custom Membership Term plugins

You can add project-specific membership term logic by implementing a new plugin that implements MembershipTermInterface and is discovered by the Membership Term manager.

Steps

1. Create a plugin class

  • Place the class in your module under src/Plugin/MembershipTerm/ (e.g. src/Plugin/MembershipTerm/CustomTerm.php).
  • Extend Drupal\crm_membership\Plugin\MembershipTermBase.
  • Add the #[MembershipTerm] PHP attribute so the plugin is discovered.

Attribute parameters (from Drupal\crm_membership\Attribute\MembershipTerm):

Parameter Type Description
id string Plugin ID (machine name). Required.
label TranslatableMarkup | null Human-readable label shown in the Membership Type form.
allowOverrideStartDate bool Whether the start date can be overridden when activating/renewing. Default false.
allowOverrideEndDate bool Whether the end date can be overridden. Default false.
durationConfigKey string | null Config key for duration (e.g. for duration_field). Optional.
timeGapKey string | null Config key for time gap between renewals. Optional.

2. Example (minimal)

<?php

declare(strict_types=1);

namespace Drupal\my_module\Plugin\MembershipTerm;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\crm\Entity\Contact;
use Drupal\crm_membership\Attribute\MembershipTerm;
use Drupal\crm_membership\Plugin\MembershipTermBase;

#[MembershipTerm(
  id: "my_custom_term",
  label: new TranslatableMarkup("My custom term"),
  allowOverrideStartDate: true,
  allowOverrideEndDate: true,
)]
final class CustomTerm extends MembershipTermBase {

  public function isActiveFor(Contact $contact): bool {
    // Your logic.
    return TRUE;
  }

  public function isExpiredFor(Contact $contact): bool {
    return FALSE;
  }

  public function activate(?array $contacts = NULL): void {
    // Create initial period(s) using $this->addMembershipPeriod().
  }

  public function renew(?array $contacts = NULL): void {
    // Add new period(s).
  }

  public function expire(): void {
    // Mark membership expired, clear current_periods as needed.
  }

  public function cancel(): void {
    // Cancel logic.
  }

  public function allowRenewal(): bool {
    return TRUE;
  }

  public function allowOverrideStartDate(): bool {
    return TRUE;
  }

  public function allowOverrideEndDate(): bool {
    return TRUE;
  }
}

The base class already implements setMembership/getMembership, getSettings, setStartDate/setEndDate, and stores startDate/endDate; you only need to implement the lifecycle and status methods (and optionally buildConfigurationForm for type configuration).

3. Reference implementation

The built-in Fixed duration plugin is a good reference: it supports configurable duration, start/end time, and time gap, and implements activation, renewal, expiration, and date overrides.

  • Class: Drupal\crm_membership\Plugin\MembershipTerm\FixedDuration
  • File: src/Plugin/MembershipTerm/FixedDuration.php
  • Attribute: src/Attribute/MembershipTerm.php

4. Configuration form (optional)

To expose settings on the Membership Type form, override buildConfigurationForm(array $current_config, FormStateInterface $form_state): array in your plugin and return a Form API array. The submitted values are stored in the type’s membership_term_config and passed to the plugin as configuration.

5. Use your plugin

  1. Clear caches so the new plugin is discovered.
  2. Edit a Membership Type (or create one) at Administration → Structure → CRM → Membership Types.
  3. Select your plugin in the “Membership term” dropdown and save. Any configuration form you added will appear there.
  4. New memberships of that type will use your plugin for activation, renewal, expiration, and status checks.