Full e-commerce functionality for your Larapen site. Sell physical and digital products with a complete shopping cart, checkout flow, coupon system, order management, and merchant feed generation.

Product Management

Create products with variants, gallery images, sale prices, stock tracking, and SEO metadata. Supports internal, external, and digital product types.

Cart & Checkout

Session-based cart for guests, database-backed for authenticated users. Automatic cart merging on login. Guest checkout support.

Order Management

Complete order lifecycle with status tracking, payment status, stock management, email notifications, and digital download delivery.

Coupons & Discounts

Percentage or fixed-amount coupons with minimum order thresholds, usage limits, date ranges, and maximum discount caps.

Merchant Feeds

Generate product feeds for Google, Bing, Facebook, Amazon, TikTok, Yandex, and Baidu with customizable field mappings.

Structured Data

Automatic schema.org/Product JSON-LD output on product pages for rich search results. Supports variants, pricing, and availability.

Use Cases

Online Store

Sell physical products with inventory tracking, shipping calculations, and coupon discounts. Customers browse categories, add to cart, checkout, and track their orders.

Digital Product Sales

Sell downloadable files (eBooks, templates, software). Digital products skip shipping, and buyers receive time-limited download links after payment. Enable the Digital Products feature first (Shop → Settings → Digital Products: off by default); leaving it off keeps the whole storefront and admin panel in physical-product mode.

Affiliate / External Products

List products that link to external retailers. External products display a “Buy Now” button linking to the external store instead of the internal cart flow. A product can list up to five stores (affiliate links, each with its own provider name): with a single active link the button goes straight to it, with several the customer picks a store first.

Multi-Channel Commerce

Use the merchant feed system to syndicate your product catalog to Google Shopping, Facebook Commerce, Amazon, TikTok Shop, and other platforms.

Requirements

  • Larapen CMS v1.0.0 or later
  • PHP 8.3+
  • MySQL 8.0+
  • At least one payment gateway add-on (e.g. Stripe) for processing payments
Note: The shop add-on installs and runs without a payment gateway, but checkout will only work with Cash on Delivery (COD) unless a payment gateway add-on is active.

Installation

Step 1: Upload the Add-on

In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.

Step 2: Activate the Add-on

Find Shop in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.

Step 3: Configure

Navigate to Admin → Shop → Settings to configure currency, tax, shipping, and checkout options. See Configuration.

Purchase Code (License Key)

Shop is sold as a separate product, so it has its own purchase code (license key), distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate Shop in Admin panel → Add-ons.

Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.

Platform / Marketplace How you get the purchase code Where to find it again
bedigit.com Store
In-site purchase (Shop)
Generated automatically when the order is paid, then sent by email, either in its own license email, or inside the order confirmation email. My Account → My Licenses on bedigit.com
Gumroad Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com
Envato Market
CodeCanyon
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. Envato account → Downloads → License certificate & purchase code
Check your spam folder. For both bedigit.com Store and Gumroad purchases, the purchase code is delivered by email. Automated license emails are very often filtered, so if the message is not in your inbox, look in your spam / junk folder before contacting support, and add our sender address to your contacts or allow list.

1. bedigit.com Store (in-site purchase)

  • As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit: buying 3 units gives 3 distinct keys).
  • It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
  • The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
  • The matching invoice is under My Account → My Orders.

2. Gumroad

  • A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
  • The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
  • When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
  • Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.

3. Envato Market (CodeCanyon)

  • Envato purchase codes are issued and delivered by Envato Market, never emailed by us, so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
  • Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
  • An Envato purchase code looks like 12345678-90ab-cdef-1234-567890abcdef (8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one.
  • Official Envato article: Where Is My Purchase Code?
Lost your purchase code? Search your mailbox (spam folder included) for “license” or “purchase code”, then check My Account → My Licenses on bedigit.com for Store and Gumroad purchases, or Downloads → License certificate on Envato. If it is still missing, open a ticket on our Help Center with your order number (Store), Gumroad sale ID or buyer email (Gumroad), or Envato username and item name (Envato).

Configuration

All settings are managed in Admin → Shop → Settings (stored in the settings table, group shop). Defaults are defined in config/shop.php.

General

Setting Description Default
shop_order_prefix Prefix for generated order numbers (e.g. ORD-20260307-00000001). ORD
shop_products_per_page Number of products per page in the catalog listing. 12
shop_sidebar_position Sidebar position on listing pages: left, right, or none. right
shop_grid_columns Number of product columns per row in grid view (1–4). 3
shop_default_view_mode Initial product listing display mode: grid or list. grid
shop_guest_checkout Allow customers to checkout without creating an account. true
shop_payment_terms_override_enabled Override the global sale terms (Settings › General › Sale Terms) for the checkout and update-access renewal pages. When off, the global settings apply. false
shop_payment_terms_enabled While overriding: require buyers to accept the sale terms before paying. global value
shop_payment_terms_page_id While overriding: the published page whose content is shown in the terms accordion. global value

Tax

Setting Description Default
shop_tax_enabled Enable tax calculation on orders. false
shop_tax_rate Tax rate as a percentage (e.g. 20 for 20%). 0
shop_tax_inclusive Whether product prices already include tax. When enabled, the tax amount is extracted from prices rather than added on top. false

Shipping

Setting Description Default
shop_shipping_enabled Enable shipping charges on orders with physical products. true
shop_free_shipping_threshold Subtotal threshold for free shipping. Set to 0 to disable. 0
shop_shipping_flat_rate Flat shipping rate applied when the order does not qualify for free shipping. 10

Digital Products

Setting Description Default
shop_digital_products_enabled Master switch for the whole digital-products feature (self-hosted downloads, versioned releases, update access, license linking, technical details). Toggled from the switch in the Digital Products tab header. When off, every digital-only field, product card, the “Create / Update license product” button and the Release Changelogs menu entry are hidden across the admin panel, and the storefront presents every product with the physical layout. Off by default so shops selling only physical products / services are never shown digital-only options. false
shop_catalog_mode Catalog Type (physical or digital): tunes the listing/detail presentation to a marketplace-style layout. Lives in the Digital Products tab and only takes effect while shop_digital_products_enabled is on, with the feature off the catalog is always presented as physical. physical
shop_digital_max_downloads Maximum number of times a digital product can be downloaded per purchase. Set to 0 for unlimited. 5
shop_digital_expiry_days Number of days after purchase before the download link expires. 30
shop_digital_update_access_months Default update-access window (in months) for updatable products: how long buyers keep downloading new versions after purchase. Overridable per product. 6
shop_update_access_renewal_enabled Allow buyers to pay to extend their update-access window once it nears or passes expiry. true
shop_update_access_renewal_percent Default renewal price to extend update access, as a percentage of the product price. Overridable per product. 50
shop_update_access_grace_days Days after update access ends during which buyers can still download before the gate applies (0 = no grace). 0
shop_update_access_syncs_license Drive the linked license key’s Expires At from update access (requires the Licenses add-on). See Updatable Products. true

Stock & Notifications

Setting Description Default
shop_low_stock_threshold Stock quantity at which products are flagged as low stock. 5
shop_notify_admin_on_order Send an email notification to admin users when a new order is placed. true
shop_notify_customer_on_order Send an order confirmation email to the customer. true

Environment Variables

Optional variables for git-backed versioned products (all have sensible defaults):

VariableDescriptionDefault
SHOP_GIT_PROCESS_TIMEOUT Max seconds a single git command may run before it is aborted. Raise it for very large repositories or slow hosts. 1800
SHOP_GIT_VERSION_LINK_TTL_HOURS How long a private per-version download link (issued to an expired-license buyer) stays valid. 48
SHOP_PHP_BINARY Path to the PHP CLI binary used to launch background release builds on the sync queue. Only needed when it cannot be auto-detected (e.g. under mod_php). (auto)
SHOP_GIT_HTTP_PROXY Proxy for git’s HTTP(S) transport. Empty means a direct connection. (empty)
Note: Environment variables are used as defaults. Settings saved in the admin panel override them.

Admin: Settings

The settings page (Shop → Settings) is organized into sections:

  • General: Order prefix, products per page, sidebar position, grid columns, default view mode, shop page title/subtitle/breadcrumb label.
  • Tax: Enable/disable tax, tax rate percentage, tax-inclusive pricing toggle.
  • Shipping: Enable/disable shipping, flat rate, free shipping threshold.
  • Checkout: Guest checkout toggle, require phone number, require shipping address.
  • Digital Products: A master Enable Digital Products switch in the card header (off by default) turns the whole feature on/off; when off, its fields are hidden here and every digital-only card, button and menu entry is hidden across the admin panel (and the storefront drops the marketplace layout). When on: Catalog Type, max downloads per purchase, download link expiry, update-access window and paid renewal options.
  • Stock: Low stock threshold.
  • Notifications: Admin notification on new order, customer order confirmation.

Admin: Products

The Products page (Shop → Products) manages your product catalog.

Products List

A paginated table showing:

  • Featured image (thumbnail)
  • Name and SKU
  • Category
  • Price (with sale price if applicable)
  • Stock quantity
  • Status (draft / published / archived)
  • Checkout type (internal / external)

Per-item actions: Edit, Delete. Bulk delete with checkbox selection.

Creating & Editing Products

The product form includes the following sections:

When editing a published product, a View button (top-right, next to Back) opens its public storefront page in a new tab. It is hidden for drafts and future-scheduled products, which have no public page yet.

Basic Information

  • Name (translatable): product title displayed in the catalog.
  • Slug (translatable): URL-friendly identifier. Auto-generated from name if empty.
  • Short Description (translatable): summary shown on listing pages.
  • Description (translatable): full product description with WYSIWYG editor.
  • Category: select from product categories.
  • SKU: stock keeping unit identifier (unique across shop products). For a digital product sold with a license key, it is also the product identifier client apps send to the License API: see License Products.
  • Status: Draft, Published, or Archived.
  • Published At: schedule publishing date.

Pricing

  • Price: regular product price.
  • Sale Price: optional discounted price (must be less than regular price to take effect).
  • Currency: set from the site’s default currency setting.

Inventory

  • Manage Stock: toggle stock tracking. When disabled, the product is always “in stock.”
  • Stock Quantity: current inventory count.

Checkout Type

  • Internal: standard add-to-cart checkout flow.
  • External: product links to one or more external stores (affiliate links). Cannot be added to cart. Stock tracking is disabled.

Images

  • Featured Image: primary product image (uses the media library).
  • Gallery Images: additional product images displayed on the detail page.

SEO

  • Meta Title (translatable)
  • Meta Description (translatable)

Feed Data

  • Brand, GTIN, MPN, Condition, Weight: used in merchant feed generation and schema.org structured data.
  • Custom Labels (0–4): for merchant feed segmentation.

Product Variants

Products can have multiple variants, each with its own:

  • Name (e.g. “Large, Red”)
  • SKU
  • Price (overrides product price if set)
  • Stock Quantity
  • Attributes (JSON: key-value pairs for size, color, etc.)
  • Active toggle

Variants are synced on product save. Removed variants are automatically deleted.

Digital Products

The Digital Product, Technical Details and License product cards (and the “Create / Update license product” button in the products list) only appear while the Enable Digital Products feature is on (Shop → Settings → Digital Products). With the feature off these cards are hidden, existing digital flags on a product are preserved on save, and the storefront renders the product with the physical layout.

When Is Digital is enabled:

  • A Digital File upload field appears. Files are stored on the configured disk (default: local) under the digital-products path.
  • Shipping is automatically excluded for digital-only orders.
  • After payment, order items receive a time-limited download link.
  • Download attempts are tracked via download_count and enforced against shop_digital_max_downloads.
  • Download links expire after shop_digital_expiry_days.

Technical Details

Digital products can advertise CodeCanyon-style stacks & compatibilities in a Technical Details card. It appears on the product form only when Is Digital is enabled, and on the storefront it is shown as a dedicated card in the product page’s right sidebar, only the fields you fill are displayed.

  • Digital file type: what kind of product this is: Code / Script, Graphic / Template, Image / Photo, Video, Audio / Music, Document, or Other. The type tailors which fields are shown: e.g. Code exposes Languages, Frameworks and Compatible Browsers, while Graphic and Image show Resolution instead. It is also displayed as the Type row in the storefront Item Details card.
  • Grouped tag lists: each field is a tag picker: Languages, Frameworks & Libraries, Compatible Browsers, Software Version, Resolution and Files Included. Pick an existing value from the suggestions or type a new one and press Enter.
  • Auto-suggestions: the picker is seeded with common values and merges in every value already used by your other products, so your catalog stays consistent while you can still add anything new on the fly.
Switching the digital file type keeps only the values from the fields that apply to the new type when you save. Values in fields that the new type hides are discarded.

Updatable Products

Enable Updatable product (shown above the Digital File field) for products that ship free updates: software, themes, templates, and similar. When enabled:

  • The per-order download limit is waived so buyers can always re-download the latest file.
  • Two extra fields appear: Update access (window in months buyers keep receiving new versions; blank uses shop_digital_update_access_months) and Update access renewal price (percentage of the product price to extend the window; blank uses shop_update_access_renewal_percent).
  • On their order page, buyers see their access status and, once it nears or passes expiry, can pay to extend update access.

License linking (with the Licenses add-on). When shop_update_access_syncs_license is on, the license key issued for an updatable purchase gets its Expires At set to the update-access window, and extending update access advances it. A key past its Expires At still validates for versions released on or before that date, only newer versions require a renewal. The verify API accepts an optional version parameter for this check.

License Products (Licenses add-on)

When the Licenses add-on is active, a digital product can be tied to a license product so that every paid order issues a license key for it. The button appears as a key icon in the products list and as a License product card at the bottom of the product edit page (digital products only, and only while Enable Digital Products is on). It reads Create license product or Update license product and requires the licenses.products.create or licenses.products.edit permission.

  • How the link is stored. The shop product is recorded as the license product’s shop marketplace listing (a row in the Licenses add-on’s licenses_product_marketplace table: listing_id = the shop product, external_id = its SKU). The shop add-on itself stores nothing about the link: the former shop_products.license_product_id column was removed by Licenses 1.0.13, which copied every existing link into that table.
  • Create makes a new license product from the shop product (name, short description, a unique slug based on the product slug) with the same SKU, then records the listing. Update refreshes the linked license product’s name and description and heals the listing.
  • One SKU on both sides. The SKU of the shop product and of its license product are kept identical: when you save either product and one side has no SKU, it is filled from the other side. Two different SKUs are never overwritten silently.
  • The button refuses to run (error toast) when:
    • the shop product and its license product carry different SKUs: align one of them, then click again;
    • the shop product SKU is already used by another license product;
    • the product is not digital.
  • License keys for orders. When an order is paid (or accepted offline), a key is issued for each order line whose shop product is listed as a license product, provided the Shop marketplace is enabled in the Licenses settings (licenses_shop_marketplace_enabled). Products without a listing issue no key.
Changing the SKU of a product you already sell. The shop SKU is the identifier client apps (add-ons, themes and applications) send to the License API as their product, and it is the SKU written in their addon.json / theme.json. If you change it on a product that customers already use, their installations may no longer match the product, change the license product SKU and the shipped manifests at the same time, and run php artisan licenses:doctor, which reports shop / license SKU mismatches (sku_mismatch) and sold products without a SKU (sku_missing).

Versioned Updates (Git)

Updatable products can be released straight from a git repository instead of a manual file upload. Toggle Versioned Updates (shown when Updatable is on) to reveal the git panel.

  • Provider: GitHub, GitLab, Bitbucket, or a custom / private git server.
  • Repository URL and optional Branch.
  • Authentication: a Token (personal access token / app password, with an optional username) or an SSH key (paste the private key; add the matching deploy key to your repository). Secrets are stored encrypted and never shown again.
  • Test connection verifies the repository is reachable with the current credentials (works before saving).
  • Create archive builds a downloadable release from a chosen annotated tag (or the latest annotated tag). The tag picker is searchable and loads tags from the repository on demand. If the repository has no annotated tag, the latest commit is used instead.

Each annotated tag becomes a release with its real tag date. The most recent release is the file buyers download. The Releases list shows the latest few (with a total count), each with a delete button (trash icon) that removes that release and its file: deleting the current one clears the product’s file until you cut a new release.

Release archives are named <project>-v<version>.zip (e.g. larapen-v1.0.8.zip), taking the project name from the repository URL.

Builds run in the background. Cloning a repository and packaging an archive can take minutes for a large repo or a slow host, so it never blocks the page. A new release shows as Building… and becomes the current file when done (or Build failed on error). Progress and errors are written to storage/logs/shop-git.log.
  • With a real queue (QUEUE_CONNECTION=database/redis): run a worker, php artisan queue:work, and it processes builds.
  • With the default sync queue: the build is launched as a detached background process automatically (no worker needed). If your PHP CLI binary cannot be auto-detected, set SHOP_PHP_BINARY in .env.
Storage: only the current release’s archive is kept on disk. Older versions are regenerated from their git tag on demand (see My Orders), so a product’s release history never accumulates ZIP files.

On the products list, git-backed updatable products show a New release button (tag icon) that cuts a fresh release from the latest annotated tag, replacing the previous file.

Release Changelogs

Every release carries a changelog. When a release is built from a tag, the changelog is generated automatically from the commit messages between that tag and the previous release (falling back to the tag’s own message). Releases are created without emailing anyone so you can review and edit the notes first.

  • Manage them under Shop → Release Changelogs (the menu entry appears only while the Digital Products feature is enabled): a searchable, filterable list of every release across all products. Add / edit / delete entries, and manually record past releases (with their own version, date and notes) that predate the git integration.
  • Edit the changelog of any release from that screen (or from the product’s release list) before publishing it.
  • Send notification: a dedicated button emails subscribed buyers the changelog for that version. It only appears when the release has a downloadable file (so notifications always point to something to download).
  • Public page: each digital, updatable product has a public changelog at /shop/product/{slug}/changelog, linked by a Changelog button in the product page’s Item Details card.

Availability & Missing Files

A digital product can only be purchased when its downloadable file actually exists (uploaded, or a release has been built). When the file is missing (not uploaded yet, no built release, or the file was deleted) the shop protects buyers automatically:

  • Storefront listings show a disabled Unavailable button, and the product page shows a “temporarily unavailable” notice instead of Buy / Add to Cart.
  • Add to Cart, Buy Now and Checkout are blocked server-side with a friendly message, so an unavailable item can never be ordered.
  • On My Orders, if a purchased item’s file is temporarily unavailable, the buyer sees a clear notice, the download button is hidden, and Extend update access is disabled (so they aren’t charged for access to a missing file).

External Products

When Checkout Type is set to External:

  • An External links card appears: add up to 5 stores, each with a provider (affiliate) name, URL, link target (new/same tab) and an active switch. Links can be removed or temporarily disabled; at least one active link is required.
  • The product cannot be added to the cart.
  • The front-end displays a “Buy Now” button. With a single active link it goes straight to the store; with two or more it opens a “Choose where to buy” dialog listing the stores (the provider name, or the link’s domain when no name is set).
  • Service plans sold through an external checkout get the same External links card on their create/edit page, and the same store picker on the storefront.
  • Stock management, digital file, and inventory fields are automatically disabled.

Admin: Categories

Product categories use the unified categories table with categorizable_type = 'product'. Categories are managed via Shop → Categories.

  • Name (translatable) and Slug (translatable, auto-generated).
  • Description (translatable) and Meta Title / Meta Description (translatable).
  • Parent Category: supports hierarchical nesting.
  • Position: ordering value.
  • Is Active toggle.
  • Featured Image via the media library.
  • Google Product Category: feed data for merchant feed generation (via shop_category_feed_data).

Admin: Orders

The Orders page (Shop → Orders) provides a list of all customer orders.

Orders List

A paginated, filterable table showing:

  • Order Number (format: ORD-YYYYMMDD-00000001)
  • Customer name & email
  • Items count
  • Total (formatted with currency)
  • Status badge (pending, processing, completed, cancelled, refunded)
  • Payment Status badge (pending, paid, failed, refunded)
  • Date

Per-item actions: View, Delete.

Order Detail

The order detail page (Shop → Orders → {order}) shows:

  • Order summary card: order number, date, status, payment status, payment method.
  • Customer info: name, email, phone, billing address, shipping address.
  • Order items table: product name, SKU, price, quantity, total, digital badge, download info.
  • Financial summary: subtotal, discount, tax, shipping, total.
  • Coupon code (if applied).
  • Transactions list: gateway, transaction ID, amount, status, type (payment / refund).
  • Notes from the customer.

Status Updates

Admin can update order status and payment status via dropdown selectors:

  • Update Status: sends PATCH admin/shop/orders/{id}/status
  • Update Payment Status: sends PATCH admin/shop/orders/{id}/payment-status

Order Statuses

Status Description
pending Order placed but not yet processed or paid.
processing Order is being prepared / fulfilled.
completed Order has been fulfilled and delivered / downloaded.
cancelled Order was cancelled. Stock is automatically restored.
refunded Payment has been refunded to the customer.

Payment Statuses

Status Description
pending Awaiting payment.
paid Payment received and confirmed.
failed Payment attempt failed.
refunded Payment has been refunded.

Admin: Coupons

The Coupons page (Shop → Coupons) manages discount codes.

Coupon Fields

Field Description
code Unique coupon code entered by the customer at checkout.
type percentage or fixed discount.
value Discount amount (percentage points or fixed currency amount).
min_order_amount Minimum order subtotal required for the coupon to apply.
max_discount Maximum discount cap (useful for percentage coupons on large orders).
max_uses Total number of times this coupon can be used across all customers.
max_uses_per_user Maximum uses per individual user.
starts_at Coupon becomes valid after this date.
expires_at Coupon expires after this date.
is_active Enable/disable the coupon.

Validation Rules

A coupon is considered valid when all of the following are true:

  1. is_active is true.
  2. Current date is after starts_at (or starts_at is null).
  3. Current date is before expires_at (or expires_at is null).
  4. used_count is less than max_uses (or max_uses is null).

A coupon is applicable to an order when it is valid AND the order subtotal meets min_order_amount.

The discount calculation never exceeds the order subtotal.

Admin: Reviews & Ratings

Customers rate products from 1 to 5 stars and leave a title and comment from the product page. Reviews are moderated on Shop → Reviews (approve, reject, reply, delete, bulk delete). Buyers of the product get a Verified purchase badge; the average rating and review count are denormalised on the product (rating_avg, rating_count) and shown on product cards, the product page and in the Product JSON-LD (aggregateRating + review) for star rich results. Listings can be sorted by Top rated.

Settings (Shop → Settings → Reviews & Ratings)

SettingDescription
shop_reviews_enabledMaster switch for the reviews block and form.
shop_reviews_guest_allowedVisitors without an account may review (name + e-mail; one review per e-mail).
shop_reviews_require_purchaseOnly customers with a paid order containing the product may review it.
shop_reviews_auto_approvePublish reviews immediately instead of holding them as pending.
shop_reviews_show_on_cardsShow the star rating on listing cards.
shop_reviews_per_pageReviews per page on the product page.
shop_review_captcha_enabled(Settings → Security) Require a CAPTCHA on the review form. A honeypot field and a 10 requests/minute throttle are always active.

Admin: Attributes & Faceted Filters

Shop → Attributes defines product attributes (Colour, Size, Material…) and their values. Attributes of type Colour swatches carry a hex colour per value. Products are tagged with values from the Attributes card of the product form. Filterable attributes appear in the shop sidebar as facets with live product counts (each facet is counted against the current result set with its own selection removed), next to the price range, customer rating and availability filters. Active filters are shown as removable chips above the grid.

Filter URL parameters

ParameterDescription
attr[<attribute-slug>][]=<value-slug>Attribute values (OR within an attribute, AND across attributes).
min_price / max_pricePrice range, applied on the current (sale) price.
rating=4Minimum average rating (4 = 4 stars & up).
in_stock=1In-stock products only.
sort=ratingSort by average rating.

The filter panel and each facet type can be switched off under Shop → Settings → Catalogue filters (shop_filters_enabled, shop_filter_price_enabled, shop_filter_stock_enabled, shop_filter_rating_enabled).

Admin: Tax Rules

Two tax modes are available (Shop → Settings → Tax, shop_tax_mode): Flat rate keeps the single shop-wide rate of earlier versions, and Tax rules applies location-based rules managed on Shop → Tax Rules.

Tax classes and rates

A tax class groups products taxed alike (Standard, Reduced, Zero…); one class is the default and products may pick another one from the product form. A tax rate belongs to a class (or to every class) and matches a country, optionally a state/region and a postcode (exact, 75* prefix or 1000-1999 range). Rates are applied in priority order; a compound rate is computed on top of the taxes with a lower priority. Rates flagged Taxes shipping also apply to the shipping amount. Tax-inclusive pricing is honoured: the net amount is derived first and the same fractions apply.

Location resolution

The applicable location is decided by shop_tax_basis: the customer's shipping address, billing address, or the store location (shop_tax_store_country / state / postcode). Before an address is entered, the checkout estimate uses, in order: the location remembered from a previous estimate, the customer's saved default address, the visitor's GeoIP country, and finally the store location. Changing the country, state or postcode at checkout recomputes the totals live (POST shop/checkout/estimate).

EU VAT (B2B)

With shop_tax_vat_enabled the checkout shows a VAT number field. Numbers are validated against the European Commission VIES service (results cached for a day). When shop_tax_reverse_charge_enabled is on, a valid number from an EU country other than the store's makes the order tax-exempt (reverse charge); shop_tax_vat_require_valid additionally blocks the checkout when VIES rejects the number. The VAT number, the per-rate breakdown and the exemption reason are stored on the order (vat_number, tax_breakdown, tax_exempt_reason) and each order line carries its tax_amount.

Front-end: Wishlist & Save for Later

A heart button on product cards and product pages adds the product to the visitor's wishlist. Logged-in customers own one list; guests get a session list that is merged into their account on login. The My Wishlist page (/shop/wishlist, also in the account menu) lets customers move items to the cart, remove them, and share the list through a private link (/shop/wishlist/{token}) that can be switched off at any time. Guest lists untouched for shop.wishlist.guest_retention_days (90 days) are pruned weekly by shop:prune-guest-wishlists.

In the cart, Save for later parks a line: it leaves the totals and the checkout but stays listed under Saved for later until it is moved back (at the current price) or removed. Saved lines survive a completed checkout.

Switches: shop_wishlist_enabled, shop_wishlist_guest_enabled, shop_save_for_later_enabled (Shop → Settings → Wishlist).

Admin: Merchant Feeds

The Merchant Feeds page (Shop → Merchant Feeds) manages product feed generation for e-commerce advertising platforms.

Supported Platforms

Platform Format Key Settings
Google Merchant Center XML Merchant Center ID, Target Country, Content Language
Bing / Microsoft XML Merchant ID, Store ID
Facebook / Meta Commerce XML Commerce Account ID, Catalog ID
Amazon Product Ads XML Seller ID, Marketplace ID, Default Category
TikTok Shop CSV TikTok Shop ID
Yandex.Market YML Shop Name, Company Name
Baidu Commerce XML Merchant ID

Per-Platform Management

For each platform, admin can:

  • Enable/Disable: toggle feed generation on or off.
  • Configure Settings: merchant ID, API keys (encrypted), currency, cache TTL, include variants, include out-of-stock products.
  • Customize Field Mappings: map platform-specific feed fields to product data properties. Override default mappings, set default values, and apply transforms.
  • Generate Feed: manually trigger feed generation.
  • Preview Feed: view a sample of the generated output.
  • Validate Feed: check the feed for structural errors.

Artisan Command

Generates feeds for all enabled platforms. Can be scheduled via Laravel’s task scheduler for automatic periodic regeneration.

Feed URLs

Generated feeds are accessible at:

For example: /feeds/products/google returns the Google Merchant Center XML feed.

Front-end: Product Catalog

Routes

MethodURLRoute NameDescription
GET /{locale}/shop shop.index.localized Product listing page
GET /{locale}/shop/category/{slug} shop.category.localized Category filtered listing
GET /{locale}/shop/product/{slug} shop.product.localized Product detail page

Non-localized variants (without {locale}) are also registered.

Product Listing Features

  • Category filtering via URL or sidebar links.
  • Search across product name, description, and SKU.
  • Sort by: newest, price (low/high), name, popularity (view count).
  • Price range filtering with min/max parameters.
  • Grid / List view toggle.
  • Pagination with configurable page size.

Product Detail Page

  • Product image gallery with featured image.
  • Price display with sale badge and discount percentage.
  • Variant selector (if variants exist).
  • Stock availability indicator.
  • Add to Cart button (or “Buy Now” link for external products).
  • Related products section (same category).
  • Schema.org JSON-LD structured data (via <x-shop-json-ld> component).

Digital products render a dedicated marketplace-style layout (gallery, item-details card, changelog link, technical details) only while the Digital Products feature is enabled. With the feature off, every product, even one still flagged digital, uses the standard physical layout.

Front-end: Shopping Cart

Routes

MethodURLRoute NameDescription
GET /{locale}/shop/cart shop.cart.localized View cart
POST /{locale}/shop/cart/add shop.cart.add.localized Add item to cart
POST /{locale}/shop/cart/update shop.cart.update.localized Update item quantity
POST /{locale}/shop/cart/remove shop.cart.remove.localized Remove item from cart
POST /{locale}/shop/cart/clear shop.cart.clear.localized Clear entire cart
POST /{locale}/shop/cart/coupon shop.cart.coupon.localized Apply coupon code
DELETE /{locale}/shop/cart/coupon shop.cart.coupon.remove.localized Remove applied coupon

Cart Behavior

  • Guest carts: stored in the database, identified by a session-based ID (shop_cart session key).
  • Authenticated carts: stored by user_id. When a user logs in, their session cart is automatically merged into their user cart.
  • Stock validation: adding items checks available stock. If the requested quantity exceeds stock, an error is returned.
  • Max quantity: configurable per-item limit (default: 99).
  • External products cannot be added to the cart; an exception is thrown with a translatable message.
  • Cart count is shared with all views via a View Composer.

Cart Totals

The CartService calculates:

  • Subtotal: sum of (price × quantity) for all items.
  • Discount: coupon discount (percentage or fixed), capped at max_discount.
  • Tax: calculated on (subtotal - discount). Supports inclusive pricing (embedded tax extraction).
  • Shipping: flat rate, waived for digital-only orders or when subtotal meets free shipping threshold.
  • Total: subtotal - discount + tax + shipping.

Front-end: Checkout

Routes

MethodURLRoute NameDescription
GET /{locale}/shop/checkout shop.checkout.localized Checkout form
POST /{locale}/shop/checkout shop.checkout.process.localized Process checkout
GET /{locale}/shop/checkout/success/{orderNumber} shop.checkout.success.localized Order success page

Checkout Flow

  1. Cart validation: redirects to cart page if empty.
  2. Guest check: if guest checkout is disabled and user is not authenticated, redirects to login.
  3. Form display: billing info (name, email, phone), billing address, shipping address, order notes, payment method selector.
  4. Form submission via CheckoutRequest validation.
  5. Order creation: the OrderService::createFromCart() method:
    • Creates the order record with all totals.
    • Creates order items from cart items.
    • Generates download links for digital products.
    • Decrements stock for managed-stock products.
    • Increments coupon usage count.
    • Sends admin and customer email notifications.
  6. Payment processing: the order implements the Payable interface, allowing the core PaymentService to route to the selected payment gateway.
  7. Success page: displays order confirmation with order number and details.
Order Numbers: Generated automatically using the pattern {prefix}-{YYYYMMDD}-{zero-padded ID}. The prefix is configurable via shop_order_prefix.

Front-end: My Orders

Routes

MethodURLRoute NameDescription
GET /{locale}/shop/my-orders shop.orders.localized List user’s orders (auth required)
GET /{locale}/shop/my-orders/{orderNumber} shop.orders.show.localized Order detail (auth required)
GET /{locale}/shop/my-orders/{orderNumber}/download/{itemId} shop.orders.download.localized Download digital product (auth required)

Digital Downloads

For digital products, the download is allowed when all conditions are met:

  • The order item is marked as is_digital with a download_link.
  • The order has been paid (payment_status = 'paid').
  • The download link has not expired (download_expires_at is in the future).
  • The download count has not reached the maximum (shop_digital_max_downloads).

Each successful download increments download_count.

Update Access & Versioned Downloads

For updatable products, the order page shows the buyer’s update-access status and, once it nears or passes expiry, an Extend button to pay for another window.

For git-backed products whose update access has lapsed, the buyer can still fetch the exact version their license covers (the newest release dated on or before their access end):

  • They click Get version … on the order page. The archive is (re)built from its git tag in the background, so the request returns immediately.
  • When it is ready, the buyer is emailed a private, time-limited download link that states its validity date (default 48h, SHOP_GIT_VERSION_LINK_TTL_HOURS).
  • Expired links and their generated files are swept automatically (shop:prune-version-downloads, daily).

Update Notifications

Buyers of an updatable product are subscribed by default to release notifications. A checkbox on the order page lets them unsubscribe. When a new version is released (and the admin chooses to notify), every subscribed buyer receives an email.

Front-end: Order Tracking

GET /{locale}/shop/order/track
Description

Guest order tracking. Customers enter their order number and billing email to view order status without logging in.

Query Parameters
order_number Required The order number (e.g. ORD-20260307-00000001)
email Required Billing email used during checkout

Payment Flow

  1. Customer selects a payment method on the checkout page.
  2. The checkout controller creates the order via OrderService::createFromCart().
  3. The PaymentService routes the order to the selected gateway.
  4. The gateway processes the payment (redirect to external page, card form, etc.).
  5. On success, the gateway calls order->markAsPaid() which sets status to completed and payment status to paid, then clears the cart.
  6. On failure, the gateway calls order->markPaymentFailed().
  7. Customer is redirected to the success URL or back to checkout.

Transactions

Payment gateways create Transaction records to track payment events:

  • Type: payment or refund
  • Status: pending, completed, or failed
  • Gateway info: gateway name, gateway transaction ID, amount, currency
  • Metadata: JSON field for gateway-specific data

Updating

There are two ways to update this add-on: via the admin panel (recommended) or manually replacing files.

Method 1: Admin Panel Upload (Recommended)

  1. Download the latest .zip file of this add-on.
  2. Go to Admin panel → Add-ons and click the Upload button.
  3. Select or drag the .zip file into the upload area.
  4. A confirmation prompt will show the current and new version numbers. Click Replace to proceed.
  5. Go to Admin panel → System Update (/admin/update) to apply any pending database migrations.

Method 2: Manual File Replacement

Step 1: Replace Files

Replace the add-on directory with the new version.

Step 2: Run Migrations

php artisan migrate

Pending migrations run once, so the command is safe to repeat.

Step 3: Clear Caches

php artisan config:clear
php artisan route:clear
php artisan view:clear

Step 4: Rebuild Assets

Backup first: Always back up your database before running migrations on a production system.
With the Licenses add-on: the link between shop products and license products is owned by the Licenses add-on. Update Licenses to 1.0.13 or later to move existing links from the removed shop_products.license_product_id column into its licenses_product_marketplace table.

Uninstallation

Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find Shop and click Deactivate.

  • Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
  • Its database tables and all the data they hold are kept, and its files stay under extensions/addons/shop/. Nothing is deleted.
  • The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
  • Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.

Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.

Removing

Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:

  1. Deactivate Shop (see Uninstallation).
  2. Click Remove on its card and confirm the prompt.

The admin panel then, in one pass:

  • runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
  • revokes the permissions declared in its addon.json;
  • rolls back its migrations (this drops its database tables and every row they hold) and purges its entries from the migrations table, so a later reinstall migrates from scratch;
  • deletes its published assets: public/addons/shop/, public/vendor/shop/ and storage/app/public/addons/shop/;
  • deletes the add-on directory extensions/addons/shop/;
  • deletes its row in the addons table (the recorded purchase code goes with it) and clears the application cache.
This cannot be undone. Back up your database before removing an add-on whose data you may still need: installing it again later creates empty tables, not your old content.

Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/shop/. In that last case, give that user write permission on the directory and on its parent, then try again.

Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.

Troubleshooting

Products not appearing in the catalog

  • Ensure the product status is Published (not Draft or Archived).
  • Check published_at: if set, it must be in the past.
  • Verify the product has at least a name set for the current locale.

Add to Cart fails: “Insufficient stock”

  • Check that stock_quantity is greater than the requested quantity.
  • If the item is already in the cart, the combined quantity must not exceed available stock.
  • Disable Manage Stock on the product to always treat it as in-stock.

Cannot add external product to cart

This is by design. External products (checkout_type = 'external') redirect to an external store. They cannot be added to the internal cart. On the front-end, a “Buy Now” link (or a store picker when the product lists several stores) is shown instead of the Add to Cart button.

Coupon not applying

  • Verify the coupon is_active is true.
  • Check starts_at and expires_at dates.
  • Confirm the order subtotal meets min_order_amount.
  • Check if used_count has reached max_uses.

Checkout fails: no payment gateways available

  • Install and activate at least one payment gateway add-on (e.g. Stripe).
  • Cash on Delivery (COD) is available as a built-in option when the shop is active.
  • Verify the payment gateway is configured correctly in its settings.

Digital download returns 403 or “Download not available”

  • Confirm the order payment_status is paid.
  • Check if the download has expired (download_expires_at).
  • Check if the maximum download count has been reached.
  • Verify the digital file exists on the configured storage disk at the stored path.

“Create / Update license product” fails

  • SKU mismatch: the shop product and its license product have different SKUs. Make them identical (on the shop product or in Licenses → Products), then click the button again.
  • SKU already used: another license product already holds this SKU. Link that license product instead, or change one of the SKUs.
  • The button only exists for digital products, with the Licenses add-on active and Enable Digital Products on.

No license key issued for a paid order

  • Check that the product has a license product (see License Products).
  • Check that the Shop marketplace is enabled in the Licenses settings (licenses_shop_marketplace_enabled).
  • Update-access renewal orders never issue keys: they only extend the existing one.

Merchant feed returns empty or 404

  • Ensure the platform is enabled in Shop → Merchant Feeds.
  • Run php artisan shop:generate-feeds to regenerate feeds.
  • Check that published products exist with is_digital = false or include_out_of_stock is enabled.
  • Verify the feed URL: /feeds/products/{platformKey} (e.g. /feeds/products/google).

Tax calculation seems incorrect

  • If using tax-inclusive pricing, the tax is extracted from (not added to) the subtotal. For a 20% rate on a $120 subtotal: tax = $120 - ($120 / 1.20) = $20.
  • For tax-exclusive pricing, tax is calculated as: (subtotal - discount) × rate / 100.
  • Verify the shop_tax_rate setting is the correct percentage (e.g. 20 for 20%, not 0.20).

Cart not merging after login

  • The session cart is identified by the shop_cart session key. If the session was cleared before login, the guest cart cannot be found.
  • Merging happens in CartService::mergeSessionCart() on the first cart access after login.

Shop v1.0.0: Part of the Larapen CMS platform.

© BeDigit. All rights reserved.

Was this article helpful?

Thank you for your feedback!

Still need help? Create a support ticket

Create a Ticket
Apr 07, 2026