Skip to content

Plugin system overview

Membership Term plugins define how membership periods are calculated and how the membership lifecycle (activation, renewal, expiration, cancellation) behaves. Each Membership Type selects one plugin and its configuration; that plugin is then used for all memberships of that type.

Manager service

Plugins are managed by:

  • Service ID: plugin.manager.crm_membership_term
  • Class: Drupal\crm_membership\Plugin\MembershipTermManager

Get the manager via the service container:

$manager = \Drupal::service('plugin.manager.crm_membership_term');
$plugin = $manager->createInstance($plugin_id, $configuration);

The Membership entity resolves its term plugin internally via getMembershipTerm() using the type’s membership_term and membership_term_config (see Entities). When using the manager directly, call setMembership() on the plugin after instantiation.

See Alter and extend for plugin discovery and hook_crm_membership_term_info.

Built-in plugins

Plugin ID Class Description
fixed_duration MembershipTerm\FixedDuration Fixed date ranges (e.g. calendar year). Configurable duration, start time, grace period, time gap, and rollover.
rolling_duration MembershipTerm\RollingDuration Duration from activation (e.g. 1 year from start). Configurable duration, grace period, and time gap; start/end can be overridden.
lifetime MembershipTerm\Lifetime No end date; membership does not expire. Start date can be overridden; renewal is a no-op.

Plugin classes live under src/Plugin/MembershipTerm/. Each is discovered via the #[MembershipTerm] PHP attribute (see Custom plugins).

Configuration keys for each plugin are documented in Configuration reference.

When plugins are used

  • Activation / renewal: Forms and other code call the term plugin’s activate() or renew() to create new membership periods (with dates calculated by the plugin).
  • Status checks: Membership::isActiveFor(Contact $contact) uses the plugin’s isActiveFor() (including grace periods). isExpiredFor() is not implemented in the base class (returns FALSE); cron uses period end_value instead.
  • Expiration: The cron/queue flow loads the membership and calls the plugin’s expire() to transition to expired and clean up periods.
  • Cancellation: cancel() exists on the interface but has no UI — call it programmatically only.

MembershipService and status field

MembershipService::isMember() and getMemberships() first query memberships with status = active. They then delegate to the term plugin’s isActiveFor() for each candidate. “Active” in query results means the status field, not a live re-evaluation of all memberships regardless of status.

See Interface for the full API and Custom plugins for implementing your own plugin.