WP Manifestindependent plugin directory
manifest / ecommerce / dokan-market-guard

Dokan Market Guard

Private state-segmented cannabis marketplace with ACF integration

by Al Amin Ahamed · github.com/mralaminahamed/dokan-market-guard · website

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/mralaminahamed/dokan-market-guard/archive/refs/heads/trunk.zip

Dokan Market Guard — Developer Guide

A closed, state-segmented marketplace: only signed-in members see it, and each member only sees what may lawfully be sold to them where they are.

What it is

A cannabis marketplace is not a shop with a login on it. Two rules apply at once and neither is optional: the catalogue may not be public, and what may be sold depends on the buyer's state. A plugin that only did the first would leak a Colorado product to a Texas buyer; one that only did the second would leave the whole catalogue indexable.

So the plugin closes the marketplace and segments it, in the same pass. Anonymous visitors are redirected away rather than shown a login wall over the content; noindex goes on the pages that must not be indexed; products are filtered by state at the query, not in the template; and purchase is blocked at woocommerce_is_purchasable, which is the last gate before money moves.

Vendors carry a state too, set at registration and editable on the user profile, so a vendor's catalogue is constrained by where they are as well as where the buyer is.

Features

Access control

  • Anonymous visitors redirected off restricted pages at template_redirect
  • noindex on the pages that must not be indexed
  • Purchase blocked at woocommerce_is_purchasable, not merely hidden
  • Age verification, checked on wp before anything renders

State segmentation

  • Product queries filtered by the viewer's state through woocommerce_product_query
  • Vendor categories restricted through dokan_product_category_args
  • Vendor state captured at dokan_new_seller_created and on the Dokan registration form
  • The same field editable on the WordPress user profile, both own and others'

Custom fields

  • ACF field groups registered on acf/init
  • Fields injected into the Dokan vendor product form
  • Server-side validation, exposed over AJAX for the form to call
  • The whole feature is behind an option — dokan_market_guard_custom_fields_enabled

Requirements

  • WordPress 6.0+
  • WooCommerce, Dokan Lite and Advanced Custom Fields — all three declared in Requires Plugins, so WordPress blocks activation until they are present
  • PHP 7.4+

Installation

git clone https://github.com/mralaminahamed/dokan-market-guard.git
cd dokan-market-guard
composer install
yarn install && yarn build

Development

composer phpcs      # WordPress coding standards
composer phpcbf     # auto-fix what it can
composer phpstan    # static analysis
composer test       # PHPUnit — unit and integration

Architecture

dokan-market-guard.php          entry point, constants, dependency guard
class-dokan-market-guard.php    singleton; init_services() wires everything
includes/
├── Core/
│   ├── AccessControl.php       who may see the marketplace at all
│   ├── StateSegmentation.php   what they may see, given where they are
│   └── CustomFields.php        ACF groups and the vendor product form
├── Dashboard/ProductSettings.php   the vendor-facing product settings
├── REST/
│   ├── Registry.php            registers the controllers
│   ├── Settings_Controller.php
│   ├── Vendors_Controller.php
│   └── Analytics_Controller.php
├── Abstracts/REST_Controller.php
├── Frontend/Hooks.php
├── Admin/Menu.php
├── Assets.php
└── Utils/
    ├── Helper.php
    └── Validator.php
tests/
├── php/Unit/                   Utils\Helper
└── php/Integration/            AccessControl

The React admin talks to the REST controllers under REST/, all of which extend Abstracts\REST_Controller — so permission checks and response shaping are written once rather than three times.

Static services, one init() each

Every service is a static class with an init() that registers its own hooks, and init_services() calls them in order. There is no container and no instance state, because none of these services has any: they are hook registrations grouped by the question they answer. AccessControl decides whether, StateSegmentation decides what, CustomFields decides which fields.

Where the gates are, and why there

Gate Hook Why there
Redirect anonymous visitors template_redirect Before any template renders, so nothing leaks in markup
noindex wp_head The only place a meta tag can go
Filter products by state woocommerce_product_query At the query — a template-level filter still runs the query and still counts the rows
Block purchase woocommerce_is_purchasable The last gate before money moves; survives a direct add-to-cart URL
Age verification wp Early enough to redirect, late enough to know the request

Filtering at the query rather than the template is the load-bearing choice. Pagination, counts and REST all read the query, so a template-level filter would show "24 products" and render nine.

Data

No custom tables. Vendor state is user meta; the feature switches are options (dokan_market_guard_custom_fields_enabled among them); field definitions belong to ACF.

License

GPL-2.0-or-later. See LICENSE.