# Wcm Data Model Subscriptions Link

> WooCommerce Memberships storage and relationship map for membership plan CPTs, user membership CPTs, post statuses, plan/user membership meta keys, rule storage, profile-field storage, order grant meta, and WooCommerce Subscriptions-linked memberships. Use when code reads or writes wc_membership_plan, wc_user_membership, wcm-* statuses, wc_memberships_rules, _subscription_id, _has_installment_plan, _free_trial_end_date, membership plan access meta, user membership dates, product/order grant meta, or when an agent needs exact Memberships CPT/meta names and the Memberships-Subscriptions relation.

- Skill: `vikingokft/wcm-data-model-subscriptions-link` (Agent Skill)
- Install (CLI): `npx skillmds add vikingokft/wcm-data-model-subscriptions-link`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vikingokft/wcm-data-model-subscriptions-link/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: vikingokft (https://skillmd.com/u/vikingokft)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/vikingokft/wcm-data-model-subscriptions-link

---


# WooCommerce Memberships: data model and Subscriptions link

Use this when an integration needs exact storage names. Prefer Memberships public APIs and objects for writes; use these keys for audits, migrations, import/export mapping, and low-level debugging.

## Core storage

| Entity | Storage | Name/key | Notes |
|---|---|---|---|
| Membership plan | CPT | `wc_membership_plan` | Registered by `WC_Memberships_Post_Types`. Not public, UI under WooCommerce when possible. |
| User membership | CPT | `wc_user_membership` | One post per user-plan membership. Not public. |
| Plan relation | WP post field | `wc_user_membership.post_parent` | This is the plan ID. Do not invent `_member_plan_id`; the installed plugin uses `post_parent`. |
| Member relation | WP post field | `wc_user_membership.post_author` | This is the member/user ID. |
| Subscription | WC order type | `shop_subscription` | From WooCommerce Subscriptions; use `wcs_get_subscription()`. |
| Membership rules | Option | `wc_memberships_rules` | Stores serialized rule arrays for all plans. Rules are not CPTs. |
| Profile field definitions | Option | `wc_memberships_profile_fields` | Definition data keyed by profile field slug. |
| Profile field values | User meta | `_wc_memberships_profile_field_{slug}` | Stored by `Profile_Field\User_Meta`. |
| Order grant marker | WC order meta | `_wc_memberships_access_granted` | Array keyed by user membership ID, with `already_granted`, `granting_order_status`, and related details. |

## Membership statuses

WP post statuses use the `wcm-` prefix. Object methods usually accept/return unprefixed slugs.

| WP status | Object status | Meaning |
|---|---|---|
| `wcm-active` | `active` | Active access. |
| `wcm-delayed` | `delayed` | Membership exists but access starts later. |
| `wcm-complimentary` | `complimentary` | Admin/complimentary access. |
| `wcm-free_trial` | `free_trial` | Added by the Subscriptions integration when a linked subscription is in trial. |
| `wcm-paused` | `paused` | Paused membership. |
| `wcm-expired` | `expired` | Expired membership. |
| `wcm-cancelled` | `cancelled` | Cancelled membership. |

Use `wc_memberships_get_user_membership_statuses()` for the installed status catalog and `wc_memberships()->get_user_memberships_instance()->get_active_access_membership_statuses()` for statuses that grant access.

## Membership plan meta

These keys are stored on `wc_membership_plan` posts and exposed by `WC_Memberships_Membership_Plan::get_meta_keys()`.

| Meta key | Purpose |
|---|---|
| `_access_method` | `manual-only`, `signup`, or `purchase` access method. |
| `_access_length` | Access length value, e.g. `unlimited`, `specific`, `fixed`, or an amount/period value depending on method. |
| `_access_start_date` | Fixed access start datetime. |
| `_access_end_date` | Fixed access end datetime. |
| `_product_ids` | Product or variation IDs that grant access. |
| `_members_area_sections` | Enabled members-area sections. |
| `_email_content` | Plan-specific email content settings. |

Use plan methods such as `get_access_method()`, `set_access_method()`, `get_product_ids()`, `set_product_ids()`, `get_access_start_date()`, and `get_access_end_date()` rather than direct meta writes.

## User membership meta

These keys are stored on `wc_user_membership` posts and exposed by `WC_Memberships_User_Membership::get_meta_keys()`.

| Meta key | Purpose |
|---|---|
| `_start_date` | Membership start datetime. |
| `_end_date` | Membership end datetime. Empty/unset can mean unlimited. |
| `_cancelled_date` | Cancellation datetime. |
| `_paused_date` | Current pause start datetime. |
| `_paused_intervals` | Historical paused intervals. |
| `_product_id` | Product or variation ID that granted access. |
| `_order_id` | Order ID that granted access. |
| `_previous_owners` | Previous owner user IDs after transfers. |
| `_renewal_login_token` | Auto-login token used for renewal flows. |
| `_locked` | Operation lock for race-sensitive flows. |

Use `wc_memberships_create_user_membership()`, `wc_memberships_get_user_membership()`, and `WC_Memberships_User_Membership` methods for writes and lifecycle side effects.

## Rule storage

Rules are stored in the `wc_memberships_rules` option, not as posts. Rule type values:

| Rule type | Purpose | Important fields |
|---|---|---|
| `content_restriction` | Restricts posts, pages, CPTs, or terms. | `content_type`, `content_type_name`, `object_ids`, `access_schedule`, `access_schedule_exclude_trial`. |
| `product_restriction` | Restricts product viewing or purchase. | Same fields plus `access_type` (`view` or `purchase`). |
| `purchasing_discount` | Applies member discounts. | `discount_type`, `discount_amount`, `active`. |

Common rule fields are `id`, `membership_plan_id`, `active`, `rule_type`, `content_type`, `content_type_name`, `object_ids`, `discount_type`, `discount_amount`, `access_type`, `access_schedule`, `access_schedule_exclude_trial`, and `meta_data`.

Use `wc_memberships()->get_rules_instance()->get_rules()`, `get_plan_rules()`, `add_rules()`, `update_rules()`, or `delete_rules()` instead of editing the option directly.

## Memberships to Subscriptions relation

WooCommerce Memberships links to WooCommerce Subscriptions by adding extra meta to the `wc_user_membership` post. The subscription itself is still a WCS `shop_subscription`.

| User membership meta | Purpose |
|---|---|
| `_subscription_id` | Linked `shop_subscription` ID. This is the primary relation key from membership to subscription. |
| `_has_installment_plan` | Flag/value used when the linked subscription is treated as an installment plan. The code stores the subscription ID when it auto-detects the flag. |
| `_free_trial_end_date` | Trial end datetime mirrored from the linked subscription trial. |

Public helpers:

```php
$integration = wc_memberships()->get_integrations_instance()->get_subscriptions_instance();
$subscription = $integration ? $integration->get_subscription_from_membership( $user_membership ) : null;
$memberships = $integration ? $integration->get_memberships_from_subscription( $subscription ) : array();

$is_linked = wc_memberships_is_user_membership_linked_to_subscription( $user_membership );
```

Do not assume a reverse meta key on the subscription. Reverse lookup queries `wc_user_membership` posts with `_subscription_id = {subscription_id}`.

## Subscription-linked lifecycle

When Subscriptions is active, Memberships may return `WC_Memberships_Integration_Subscriptions_User_Membership` for linked memberships.

Important behavior:

- Linking calls `WC_Memberships_Integration_Subscriptions_User_Membership::set_subscription_id()` and fires `wc_memberships_user_membership_linked_to_subscription`.
- Unlinking deletes `_subscription_id` and fires `wc_memberships_user_membership_unlinked_from_subscription`.
- Subscription trial dates can set membership status to `free_trial` and write `_free_trial_end_date`.
- Subscription date/status changes can update linked membership dates/statuses.
- If a plan is granted by subscription products, Memberships checks whether the subscription product grants the plan and may keep access tied to subscription activity.
- Installment plan behavior differs: completion can unlink the subscription while keeping membership access according to the plan rules.

## Gifting and Memberships

WooCommerce Subscriptions Gifting changes who receives membership access when the gifted subscription product grants a Memberships plan.

Storage bridge:

- Gifted subscription stores recipient user on subscription meta `_recipient_user` after recipient account resolution.
- Parent order item stores `wcsg_recipient = wcsg_recipient_id_{user_id}`.
- Memberships grant filtering uses `wcsg_recipient` to grant access to recipient users instead of the purchaser for gifted items.
- The membership still stores the linked subscription in `_subscription_id`.

If an order has the same membership-granting product for several recipients, do not pick the first subscription in the order. Use the WCSG/Memberships integration logic or query recipient subscriptions before assigning `_subscription_id`.

## Safe query patterns

```php
// Memberships for a subscription.
$memberships = get_posts( array(
    'post_type'      => 'wc_user_membership',
    'post_status'    => wc_memberships_get_user_membership_statuses( false ),
    'fields'         => 'ids',
    'posts_per_page' => -1,
    'meta_query'     => array(
        array(
            'key'   => '_subscription_id',
            'value' => $subscription_id,
        ),
    ),
) );

// Prefer API for normal code.
$user_membership = wc_memberships_get_user_membership( $user_id, $plan_id );
```

## Common mistakes

```php
// WRONG: this key is not the plan relation in the installed plugin.
$plan_id = get_post_meta( $membership_id, '_member_plan_id', true );

// RIGHT: use the object or post_parent.
$membership = wc_memberships_get_user_membership( $membership_id );
$plan_id = $membership ? $membership->get_plan_id() : 0;

// WRONG: raw post status write misses Memberships side effects.
wp_update_post( array( 'ID' => $membership_id, 'post_status' => 'wcm-active' ) );

// RIGHT: use object status API with unprefixed status.
$membership->update_status( 'active' );
```

## Cross-references

- Use `wcm-membership-hooks` for lifecycle hooks and REST/webhook extension points.
- Use `wcm-access-discounts` for access checks, restrictions, drip timing, and member discounts.
- Use `wcs-data-model-switching-gifting` for Subscriptions order type, subscription meta, switch data, and gifting data.

