justinholtweb/craft-headcount
最新稳定版本:5.0.2
Composer 安装命令:
composer require justinholtweb/craft-headcount
包简介
Full-featured membership plugin for Craft CMS with Stripe + PayPal integration, tiered access, content gating, drip content, and subscription management.
README 文档
README
Full-featured membership and subscription management plugin for Craft CMS 5. Stripe and PayPal integration, tiered access control, content gating, drip content, and a complete subscription lifecycle -- built for the Craft ecosystem.
Features
- Stripe & PayPal -- Recurring payments via Stripe Checkout Sessions and PayPal Subscriptions API v2
- Membership Plans -- Tiered plans with configurable billing intervals (day/week/month/year), trial periods, and per-plan pricing
- Content Gating -- Restrict entries by section, entry type, category, or individual entry with redirect, paywall, or hide behaviors
- Drip Content -- Schedule content to unlock N days after subscription start
- User Group Sync -- Automatically add/remove users from Craft user groups based on subscription status
- Coupons & Discounts -- Percentage or flat-rate codes synced to Stripe Coupons
- Member Portal -- Self-service subscription management via Stripe Customer Portal
- Reporting -- MRR, churn rate, trial conversion, growth metrics, and dashboard widgets
- Transactional Emails -- Welcome, receipt, payment failed, trial ending, cancellation, and drip unlock notifications via Craft's mailer
- REST API -- JSON endpoints for plans, subscriptions, checkout, portal, and member info with API key auth
- Twig Extension --
craft.headcountvariable and{% headcountGate %}tag for template-level gating - CLI Commands --
headcount/subscriptions/expire,headcount/subscriptions/sync,headcount/sync/plans,headcount/sync/status
Requirements
- Craft CMS 5.0+
- PHP 8.2+
- Stripe account (for Stripe payments)
- PayPal Business account (optional, for PayPal payments)
Installation
composer require justinholtweb/craft-headcount php craft plugin/install headcount
Or install from the Craft Plugin Store.
Quick Start
1. Configure Payment Gateways
Navigate to Headcount > Settings and enter your Stripe API keys. Optionally enable PayPal.
Settings can be overridden via config/headcount.php:
<?php return [ 'stripeSecretKey' => getenv('STRIPE_SECRET_KEY'), 'stripePublishableKey' => getenv('STRIPE_PUBLISHABLE_KEY'), 'stripeWebhookSecret' => getenv('STRIPE_WEBHOOK_SECRET'), 'paypalClientId' => getenv('PAYPAL_CLIENT_ID'), 'paypalClientSecret' => getenv('PAYPAL_CLIENT_SECRET'), 'paypalEnabled' => false, 'defaultCurrency' => 'USD', 'checkoutSuccessUrl' => '/membership/thank-you', 'checkoutCancelUrl' => '/membership/plans', 'loginUrl' => '/login', 'pricingUrl' => '/membership/plans', ];
2. Create Plans
Go to Headcount > Plans and create membership tiers. Each plan maps to:
- A Stripe Price (auto-created on first sync, or enter an existing Price ID)
- A Craft User Group (members are automatically added/removed)
- A billing interval, price, and optional trial period
3. Set Up Webhooks
Point your Stripe webhook to:
https://yoursite.com/actions/headcount/webhook/stripe
Required Stripe events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.paidinvoice.payment_failedcustomer.subscription.trial_will_end
For PayPal:
https://yoursite.com/actions/headcount/webhook/paypal
4. Create Access Rules
Go to Headcount > Access Rules to gate content. Rules can target a section, entry type, category, or individual entry. Choose a behavior:
| Behavior | Effect |
|---|---|
| Redirect | 302 redirect to login or pricing page |
| Paywall | Show truncated teaser content with a CTA |
| Hide | Return 404 for unauthorized users |
5. Add Checkout to Templates
{# Pricing page #} {% for plan in craft.headcount.plans() %} <div class="plan"> <h3>{{ plan.name }}</h3> <p>{{ plan.currency|upper }} {{ plan.price|number_format(2) }}/{{ plan.billingInterval }}</p> {% if plan.features %} <ul> {% for feature in plan.features %} <li>{{ feature }}</li> {% endfor %} </ul> {% endif %} <form method="post"> {{ csrfInput() }} <input type="hidden" name="action" value="headcount/checkout/create-session"> <input type="hidden" name="planHandle" value="{{ plan.handle }}"> <button type="submit">Subscribe</button> </form> </div> {% endfor %}
Template Reference
Template Variable: craft.headcount
{# Check if current user has any active subscription #} {% if craft.headcount.isSubscribed() %} {# Check specific plan #} {% if craft.headcount.isSubscribed('pro-monthly') %} {# Check if user can access an entry (respects gating + drip) #} {% if craft.headcount.canAccess(entry) %} {# Get current user's active subscriptions #} {% set subs = craft.headcount.subscriptions() %} {# Get all enabled plans #} {% set plans = craft.headcount.plans() %} {# Get a specific plan #} {% set pro = craft.headcount.plan('pro-monthly') %} {# Checkout URL (form POST is preferred, but this works for links) #} {{ craft.headcount.checkoutUrl('pro-monthly') }} {# Customer Portal URL #} {{ craft.headcount.portalUrl() }} {# Drip content checks #} {% if craft.headcount.isUnlocked(entry) %} {{ craft.headcount.unlocksIn(entry) }} {# days remaining #} {# Coupon input field helper #} {{ craft.headcount.couponField() }} {# Raw subscription query #} {% set query = craft.headcount.subscriptionQuery() %}
Twig Tag: {% headcountGate %}
{# Gate content to any active subscriber #} {% headcountGate %} <p>Members-only content here.</p> {% endheadcountGate %} {# Gate to a specific plan #} {% headcountGate planHandle='pro-monthly' %} <p>Pro content here.</p> {% endheadcountGate %}
Using Craft's Built-in User Group Checks
Since Headcount syncs subscriptions to Craft user groups, you can also use native Craft checks:
{% if currentUser and currentUser.isInGroup('pro') %}
<p>Pro member content</p>
{% endif %}
REST API
All endpoints are prefixed with /actions/headcount/api/.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /plans |
Public | List all enabled plans |
| GET | /plan?handle=xxx |
Public | Get a specific plan |
| GET | /subscriptions |
Session/API key | List current user's subscriptions |
| GET | /subscription?id=xxx |
Session/API key | Get a specific subscription |
| POST | /checkout |
Session | Create a checkout session |
| GET | /portal |
Session | Get Stripe Customer Portal URL |
| GET | /member |
Session/API key | Get current member info with subscriptions |
Authentication: Session-based for logged-in users, or pass an API key via X-Headcount-Api-Key header or ?apiKey= query parameter.
CLI Commands
# Process expired subscriptions (cancel those past period end) php craft headcount/subscriptions/expire # Sync all active subscription statuses from Stripe/PayPal php craft headcount/subscriptions/sync # Sync plans to payment providers (create Stripe Products/Prices) php craft headcount/sync/plans # Check sync health and display stats php craft headcount/sync/status
Events
Headcount fires events you can listen to in custom modules or plugins:
use justinholtweb\headcount\services\Subscriptions; use justinholtweb\headcount\events\SubscriptionEvent; use yii\base\Event; Event::on( Subscriptions::class, Subscriptions::EVENT_AFTER_CREATE_SUBSCRIPTION, function (SubscriptionEvent $event) { $subscription = $event->subscription; // Custom logic after subscription creation } );
Available events on Subscriptions service:
EVENT_BEFORE_CREATE_SUBSCRIPTION/EVENT_AFTER_CREATE_SUBSCRIPTIONEVENT_BEFORE_UPDATE_SUBSCRIPTION/EVENT_AFTER_UPDATE_SUBSCRIPTIONEVENT_BEFORE_CANCEL_SUBSCRIPTION/EVENT_AFTER_CANCEL_SUBSCRIPTION
Outgoing Webhooks
Configure a webhook URL in Headcount > Settings to receive POST notifications for subscription lifecycle events. Payloads are signed with HMAC-SHA256 via the X-Headcount-Signature header.
Events: subscription.created, subscription.updated, subscription.canceled, subscription.expired, member.upgraded, member.downgraded
Architecture
Headcount uses a hybrid architecture:
- Subscription Element -- A custom Craft element type that stores billing state (gateway IDs, status, dates, amounts) in the
headcount_subscriptionstable linked to theelementstable - User Group Sync -- Active subscriptions automatically add users to the plan's mapped Craft user group; cancellation/expiration removes them
- Content Gating -- Hooks into
Entry::EVENT_AUTHORIZE_VIEWat the system level, so gating works regardless of template code - Payment Gateways -- Stripe uses the
stripe/stripe-phpSDK with theStripeClientinstance pattern; PayPal uses the REST API v2 directly via Guzzle
Database Tables
| Table | Purpose |
|---|---|
headcount_plans |
Membership plan definitions |
headcount_subscriptions |
Subscription element content (FK to elements) |
headcount_access_rules |
Content gating rules |
headcount_drip_schedules |
Drip content timing |
headcount_coupons |
Discount codes |
headcount_webhook_logs |
Incoming webhook event log (idempotency) |
Support
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: proprietary
- 更新时间: 2026-06-11