PHPackages                             craftcms/digital-products - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. craftcms/digital-products

ActiveCraft-plugin[API Development](/categories/api)

craftcms/digital-products
=========================

Sell digital product licenses with Craft Commerce

4.0.3(1y ago)1814.7k↓39.6%9[11 issues](https://github.com/craftcms/commerce-digital-products/issues)[2 PRs](https://github.com/craftcms/commerce-digital-products/pulls)3MITPHPPHP ^8.2CI passing

Since Apr 4Pushed 1mo ago6 watchersCompare

[ Source](https://github.com/craftcms/commerce-digital-products)[ Packagist](https://packagist.org/packages/craftcms/digital-products)[ RSS](/packages/craftcms-digital-products/feed)WikiDiscussions 4.x Synced today

READMEChangelog (6)Dependencies (5)Versions (43)Used By (3)

[![Digital Products icon](./src/icon.svg)](./src/icon.svg)

Digital Products
================

[](#digital-products)

This plugin makes it possible to sell licenses for digital products with [Craft Commerce](https://craftcms.com/commerce).

Requirements
------------

[](#requirements)

Digital Products requires Craft 5.0.0 and Craft Commerce 5.0.0 or later.

Installation
------------

[](#installation)

You can install this plugin from the Plugin Store or with Composer.

#### From the Plugin Store

[](#from-the-plugin-store)

Go to the Plugin Store in your project’s Control Panel and search for “Digital Products”. Then click on the “Install” button in its modal window.

#### With Composer

[](#with-composer)

Open your terminal and run the following commands:

```
# go to the project directory
cd /path/to/my-project.test

# tell Composer to load the plugin
composer require craftcms/digital-products

# tell Craft to install the plugin
./craft install/plugin digital-products
```

Events
------

[](#events)

### The `beforeSaveProductType` and `afterSaveProductType` events

[](#the-beforesaveproducttype-and-aftersaveproducttype-events)

Plugins can be notified immediately before or after a product type is saved so your plugin can take action if needed:

```
use craft\digitalproducts\events\ProductTypeEvent;
use craft\digitalproducts\services\ProductTypes;
use yii\base\Event;

// ...

Event::on(
    ProductTypes::class,
    ProductTypes::EVENT_BEFORE_SAVE_PRODUCTTYPE,
    function(ProductTypeEvent $e) {
        // Custom code to be executed when a product type is saved
    }
);
```

### The `beforeGenerateLicenseKey` event

[](#the-beforegeneratelicensekey-event)

Plugins get a chance to provide a license key instead of relying on Digital Products to generate one.

```
use craft\digitalproducts\elements\License;
use craft\digitalproducts\events\GenerateKeyEvent;
use craft\digitalproducts\Plugin as DigitalProducts;
use yii\base\Event;

// ...

Event::on(
    License::class,
    License::EVENT_GENERATE_LICENSE_KEY,
    function(GenerateKeyEvent $e) {
        $licenseService = DigitalProducts::getInstance()->getLicenses();

        do {
            $licenseKey = // custom key generation logic...
        } while (!$licenseService->isLicenseKeyUnique($licenseKey));

        $e->licenseKey = $licenseKey;
    }
);
```

Eager loading
-------------

[](#eager-loading)

Both licenses and products have several eager-loadable properties.

### Licenses

[](#licenses)

- `product` allows you to eager-load the product associated with the license.
- `order` allows you to eager-load the order associated with the license, if any.
- `owner` allows you to eager-load the Craft user that owns the license, if any.

### Products

[](#products)

- `existingLicenses` eager-loads all the existing licenses for the currently logged in Craft User.

Examples
--------

[](#examples)

### Displaying the licensed product for the currently logged in Craft User.

[](#displaying-the-licensed-product-for-the-currently-logged-in-craft-user)

```
{% if currentUser %}
    {% set licenses = craft.digitalProducts
        .licenses
        .owner(currentUser)
        .with(['product', 'order'])
        .all()
    %}

    Licenses
    {% if licenses %}

                    Licensed product
                    License date
                    Order

            {% for license in licenses %}

                        {{ license.product.title }}

                    {{ license.dateCreated|date('Y-m-d H:i:s') }}

                        {% if license.orderId %}

                                Order no. {{ license.orderId }}

                        {% endif %}

            {% endfor %}

    {% endif %}
{% else %}
    Please log in first
{% endif %}
```

### Checking if currently logged in user is licensed to access a product.

[](#checking-if-currently-logged-in-user-is-licensed-to-access-a-product)

```
{% set products = craft.digitalProducts
    .products
    .type('onlineCourses')
    .with(['existingLicenses'])
    .all()
%}

{% if products|length %}

                Product
                License status

            {% for product in products %}

                    {{ product.title }}

                        {% if product.existingLicenses|length %}
                            You already own this product.
                        {% else %}
                            Get it now!
                        {% endif %}

            {% endfor %}

{% endif %}
```

GraphQL
-------

[](#graphql)

Digital products may be queried with GraphQL. Please read the [getting started docs](https://docs.craftcms.com/v3/graphql.html) to get up to speed with how Craft CMS handles GraphQL requests.

The GraphQL implementation provides two query options: `digitalProducts` for returning multiple products, and `digitalProduct` for returning a single product.

### An example query and response

[](#an-example-query-and-response)

#### Query payload

[](#query-payload)

```
query {
    digitalProducts(type: "eBooks", limit: 2) {
        title,
        sku,
        price
    }
}
```

#### The response

[](#the-response)

```
{
    "data": {
        "digitalProducts": [
            {
                "title": "Breaking Bad: The Recipes",
                "sku": "BB-TR",
                "price": 14.99
            },
            {
                "title": "The Clone Wars: Color The Clones",
                "sku": "TCW-CTC",
                "price": 7.95
            }
        ]
    }
}
```

#### The `digitalProducts`/`digitalProduct` query

[](#the-digitalproductsdigitalproduct-query)

Both the queries use the same argument set.

ArgumentTypeDescription`id``[QueryArgument]`Narrows the query results based on the elements’ IDs.`uid``[String]`Narrows the query results based on the elements’ UIDs.`status``[String]`Narrows the query results based on the elements’ statuses.`unique``Boolean`Determines whether only elements with unique IDs should be returned by the query.`title``[String]`Narrows the query results based on the elements’ titles.`sku``[String]`Narrows the query results based on the digital products’ SKUs.`slug``[String]`Narrows the query results based on the elements’ slugs.`uri``[String]`Narrows the query results based on the elements’ URIs.`search``String`Narrows the query results to only elements that match a search query.`relatedTo``[Int]`Narrows the query results to elements that relate to *any* of the provided element IDs. This argument is ignored, if `relatedToAll` is also used.`relatedToAll``[Int]`Narrows the query results to elements that relate to *all* of the provided element IDs. Using this argument will cause `relatedTo` argument to be ignored.`ref``[String]`Narrows the query results based on a reference string.`fixedOrder``Boolean`Causes the query results to be returned in the order specified by the `id` argument.`inReverse``Boolean`Causes the query results to be returned in reverse order.`dateCreated``[String]`Narrows the query results based on the elements’ creation dates.`dateUpdated``[String]`Narrows the query results based on the elements’ last-updated dates.`offset``Int`Sets the offset for paginated results.`limit``Int`Sets the limit for paginated results.`orderBy``String`Sets the field the returned elements should be ordered by`type``[String]`Narrows the query results based on the digital products’ prdocut type handles.`typeId``[QueryArgument]`Narrows the query results based on the digital products’ product types, per the types’ IDs.`postDate``[String]`Narrows the query results based on the digital products’ post dates.`before``String`Narrows the query results to only digital products that were posted before a certain date.`after``String`Narrows the query results to only digital products that were posted on or after a certain date.`expiryDate``[String]`Narrows the query results based on the digital products’ expiry dates.

###  Health Score

56

—

FairBetter than 97% of packages

Maintenance57

Moderate activity, may be stable

Popularity36

Limited adoption so far

Community28

Small or concentrated contributor base

Maturity88

Battle-tested with a long release history

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~82 days

Recently: every ~119 days

Total

37

Last Release

38d ago

Major Versions

2.4.3.2 → 3.0.x-dev2022-05-04

3.2.3 → 4.0.02024-03-27

3.2.4 → 4.0.32025-02-03

3.x-dev → 4.x-dev2026-05-26

4.x-dev → 5.x-dev2026-05-27

PHP version history (2 changes)3.0.x-devPHP ^8.0.2

4.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/3ccdf8b493035de2343c55bd889513e3af5c04d5823482a2b186ad16adb1c3e3?d=identicon)[brandonkelly](/maintainers/brandonkelly)

---

Top Contributors

[![nfourtythree](https://avatars.githubusercontent.com/u/266453?v=4)](https://github.com/nfourtythree "nfourtythree (111 commits)")[![andris-sevcenko](https://avatars.githubusercontent.com/u/1891118?v=4)](https://github.com/andris-sevcenko "andris-sevcenko (105 commits)")[![lukeholder](https://avatars.githubusercontent.com/u/133571?v=4)](https://github.com/lukeholder "lukeholder (59 commits)")[![brandonkelly](https://avatars.githubusercontent.com/u/47792?v=4)](https://github.com/brandonkelly "brandonkelly (36 commits)")[![angrybrad](https://avatars.githubusercontent.com/u/61869?v=4)](https://github.com/angrybrad "angrybrad (31 commits)")[![pdaleramirez](https://avatars.githubusercontent.com/u/4172750?v=4)](https://github.com/pdaleramirez "pdaleramirez (8 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![kennethormandy](https://avatars.githubusercontent.com/u/1581276?v=4)](https://github.com/kennethormandy "kennethormandy (4 commits)")[![aloco](https://avatars.githubusercontent.com/u/11661125?v=4)](https://github.com/aloco "aloco (3 commits)")[![brianjhanson](https://avatars.githubusercontent.com/u/1843073?v=4)](https://github.com/brianjhanson "brianjhanson (2 commits)")[![timkelty](https://avatars.githubusercontent.com/u/18329?v=4)](https://github.com/timkelty "timkelty (2 commits)")[![MakeilaLundy](https://avatars.githubusercontent.com/u/19892516?v=4)](https://github.com/MakeilaLundy "MakeilaLundy (1 commits)")[![i-just](https://avatars.githubusercontent.com/u/4500340?v=4)](https://github.com/i-just "i-just (1 commits)")[![olivierbon](https://avatars.githubusercontent.com/u/146041?v=4)](https://github.com/olivierbon "olivierbon (1 commits)")[![stevenvandemoortele](https://avatars.githubusercontent.com/u/2240463?v=4)](https://github.com/stevenvandemoortele "stevenvandemoortele (1 commits)")

---

Tags

craft-commercecraftcmscraftcms-pluginyii2craftcmsproductscommercedigital

### Embed Badge

![Health badge](/badges/craftcms-digital-products/health.svg)

```
[![Health](https://phpackages.com/badges/craftcms-digital-products/health.svg)](https://phpackages.com/packages/craftcms-digital-products)
```

###  Alternatives

[craftcms/commerce

Craft Commerce

240425.9k185](/packages/craftcms-commerce)[craftcms/element-api

Create a JSON API for your elements in Craft

502710.4k10](/packages/craftcms-element-api)[verbb/events

A full-featured plugin for event management and ticketing.

2311.9k](/packages/verbb-events)[craftcms/apple-news

Publish Craft CMS entries to Apple News

4223.5k](/packages/craftcms-apple-news)[wrav/oembed

A simple plugin to extract media information from websites, like youtube videos, twitter statuses or blog articles.

36208.3k3](/packages/wrav-oembed)[verbb/gift-voucher

Sell and redeem digital gift vouchers for Craft Commerce.

1322.9k1](/packages/verbb-gift-voucher)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
