DO

dokan-backend-dev

Provides conventions for developing Dokan backend PHP code, including namespace structure and hook management.

Install

mkdir -p .claude/skills/dokan-backend-dev && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/12198" && unzip -o skill.zip -d .claude/skills/dokan-backend-dev && rm skill.zip

Installs to .claude/skills/dokan-backend-dev

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Add or modify Dokan backend PHP code following project conventions. Use when creating new classes, methods, hooks, REST controllers, or modifying existing backend code. Invoke before writing PHP unit tests.
206 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • Create new PHP classes or services following conventions
  • Add hooks, filters, or REST endpoints
  • Modify existing backend PHP code
  • Implement the Manager pattern for subsystems
  • Register services using League Container

How it works

The skill provides guidance on Dokan backend PHP development, covering namespace, class conventions, Manager pattern, dependency injection, and REST API controllers.

Inputs & outputs

You give it
Requirements for new or modified Dokan backend PHP code
You get back
PHP code adhering to Dokan's backend development standards

When to use dokan-backend-dev

  • Create new PHP classes or services
  • Add new REST endpoints or hooks
  • Modify backend PHP code
  • Write PHP unit tests

About this skill

Dokan Backend Development

This skill provides guidance for developing Dokan Lite backend PHP code according to project standards.

When to Use This Skill

Invoke this skill before:

  • Writing new PHP unit tests
  • Creating new PHP classes or services
  • Modifying existing backend PHP code
  • Adding hooks, filters, or REST endpoints

Namespace & File Structure

  • Root namespace: WeDevs\Dokan\
  • PSR-4 autoloading: WeDevs\Dokan\ maps to includes/
  • File path follows namespace: WeDevs\Dokan\Order\Managerincludes/Order/Manager.php
  • Third-party (Mozart): WeDevs\Dokan\ThirdParty\Packages\lib/packages/

Class Conventions

Method & Property Naming

  • Methods: snake_case (WordPress convention) — e.g., register_routes(), get_stores()
  • Properties: typed (PHP 7.4+) — e.g., protected bool $should_adjust_refund = true;
  • Constants: UPPER_SNAKE_CASE

Manager Pattern

Most subsystems use a Manager class as the primary facade:

namespace WeDevs\Dokan\Order;

class Manager {
    public function all( $args = [] ) { ... }
    public function get( $id ) { ... }
    public function create( $args ) { ... }
}

Access via: dokan()->order->all()

Hookable Interface

Classes that register WordPress hooks should implement Hookable:

namespace WeDevs\Dokan\Product;

use WeDevs\Dokan\Contracts\Hookable;

class Hooks implements Hookable {
    public function register_hooks(): void {
        add_action( 'save_post_product', [ $this, 'handle_product_save' ], 10, 2 );
        add_filter( 'dokan_product_listing_args', [ $this, 'filter_listing_args' ] );
    }
}

Classes implementing Hookable are auto-registered in CommonServiceProvider — their hooks load automatically.

Dependency Injection

Uses League Container v4 (namespaced under WeDevs\Dokan\ThirdParty\Packages\League\Container).

Registering Services

Add to the appropriate ServiceProvider in includes/DependencyManagement/Providers/:

// In ServiceProvider.php (main) for core services:
protected $services = [
    'my_service' => \WeDevs\Dokan\MyDomain\Manager::class,
];

// In CommonServiceProvider.php for Hookable classes:
protected $services = [
    \WeDevs\Dokan\MyDomain\Hooks::class,
];

Accessing Services

// Via magic getter (most common)
dokan()->order->get( $order_id );
dokan()->vendor->get( $vendor_id );

// Via container directly
dokan()->get_container()->get( 'order' );

Base Service Provider Helper

Use share_with_implements_tags() to auto-tag services by their interfaces:

$this->share_with_implements_tags( MyService::class );

REST API Controllers

Controller Hierarchy

WP_REST_Controller (WordPress core)
└── DokanBaseController (dokan/v1)
    ├── DokanBaseAdminController (dokan/v1/admin) — admin-only endpoints
    ├── DokanBaseVendorController (dokan/v1) — vendor endpoints (uses VendorAuthorizable trait)
    └── DokanBaseCustomerController (dokan/v1) — customer endpoints

Choose the appropriate base class:

  • DokanBaseAdminController — For admin-only endpoints (dokan/v1/admin/*). Has built-in check_permission() checking manage_woocommerce capability.
  • DokanBaseVendorController — For vendor endpoints. Includes VendorAuthorizable trait for store access checks.
  • DokanBaseController — For general endpoints that don't fit the above.

Note: Some older controllers extend WP_REST_Controller directly (e.g., StoreController, WithdrawController). New controllers should extend one of the Dokan base classes.

Full Controller Example

namespace WeDevs\Dokan\REST;

use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WeDevs\Dokan\Traits\RESTResponseError;

class MyResourceController extends DokanBaseAdminController {

    use RESTResponseError;

    /**
     * Route base.
     *
     * @var string
     */
    protected $rest_base = 'my-resource';

    /**
     * Register routes.
     *
     * @return void
     */
    public function register_routes() {
        register_rest_route(
            $this->namespace, '/' . $this->rest_base, [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [ $this, 'get_items' ],
                    'args'                => array_merge(
                        $this->get_collection_params(),
                        [
                            'status' => [
                                'description' => __( 'Filter by status.', 'dokan-lite' ),
                                'type'        => 'string',
                                'enum'        => [ 'active', 'inactive' ],
                                'default'     => 'active',
                            ],
                        ]
                    ),
                    'permission_callback' => [ $this, 'check_permission' ],
                ],
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [ $this, 'create_item' ],
                    'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
                    'permission_callback' => [ $this, 'check_permission' ],
                ],
                'schema' => [ $this, 'get_item_schema' ],
            ]
        );

        register_rest_route(
            $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', [
                'args' => [
                    'id' => [
                        'description' => __( 'Unique identifier for the object.', 'dokan-lite' ),
                        'type'        => 'integer',
                    ],
                ],
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [ $this, 'get_item' ],
                    'permission_callback' => [ $this, 'check_permission' ],
                ],
                [
                    'methods'             => WP_REST_Server::EDITABLE,
                    'callback'            => [ $this, 'update_item' ],
                    'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
                    'permission_callback' => [ $this, 'check_permission' ],
                ],
                [
                    'methods'             => WP_REST_Server::DELETABLE,
                    'callback'            => [ $this, 'delete_item' ],
                    'permission_callback' => [ $this, 'check_permission' ],
                ],
            ]
        );

        // Batch endpoint
        register_rest_route(
            $this->namespace, '/' . $this->rest_base . '/batch', [
                [
                    'methods'             => WP_REST_Server::EDITABLE,
                    'callback'            => [ $this, 'batch_items' ],
                    'permission_callback' => [ $this, 'check_permission' ],
                    'args'                => $this->get_public_batch_schema()['properties'],
                ],
                'schema' => [ $this, 'get_public_batch_schema' ],
            ]
        );
    }
}

Prepare Item for Response

Every controller must implement prepare_item_for_response(). This method transforms the internal data model into the REST API response shape, adds HATEOAS links, and applies an extensibility filter:

/**
 * Prepare a single item for response.
 *
 * @param MyModel         $item    Data object.
 * @param WP_REST_Request $request Request object.
 *
 * @return WP_REST_Response
 */
public function prepare_item_for_response( $item, $request ) {
    $data = [
        'id'          => absint( $item->get_id() ),
        'title'       => $item->get_title(),
        'status'      => $item->get_status(),
        'amount'      => floatval( $item->get_amount() ),
        'created'     => mysql_to_rfc3339( $item->get_date() ),
    ];

    $data = apply_filters( 'dokan_rest_prepare_my_resource_data', $data, $item, $request );

    $response = rest_ensure_response( $data );
    $response->add_links( $this->prepare_links( $item, $request ) );

    return apply_filters( 'dokan_rest_prepare_my_resource_object', $response, $item, $request );
}

Prepare Links (HATEOAS)

Provide self and collection links for discoverability:

/**
 * Prepare links for the request.
 *
 * @param MyModel         $item    Object data.
 * @param WP_REST_Request $request Request object.
 *
 * @return array Links for the given item.
 */
protected function prepare_links( $item, $request ) {
    return [
        'self'       => [
            'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $item->get_id() ) ),
        ],
        'collection' => [
            'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
        ],
    ];
}

Collection Response with Pagination

Use format_collection_response() (inherited from DokanBaseController) to add pagination headers:

public function get_items( $request ) {
    $args = [
        'number' => (int) $request['per_page'],
        'offset' => (int) ( $request['page'] - 1 ) * $request['per_page'],
    ];

    $items       = $this->get_my_items( $args );
    $total_items = $this->get_my_items_count( $args );

    $data = [];
    foreach ( $items as $item ) {
        $item_data = $this->prepare_item_for_response( $item, $request );
        $data[]    = $this->prepare_response_for_collection( $item_data );
    }

    $response = rest_ensure_response( $data );
    $response = $this->format_collection_response( $response, $request, $total_items );

    return $response;
}

format_collection_response() sets these headers automatically:

  • X-WP-Total — Total item count
  • X-WP-TotalPages — Total page count
  • `Link: <url>; rel="pr

Content truncated.

When not to use it

  • When writing new PHP unit tests (this skill is invoked before)
  • When using older controllers that extend WP_REST_Controller directly
  • When concatenating translated strings instead of using sprintf()

Limitations

  • Methods should use snake_case
  • Properties should be typed (PHP 7.4+)
  • New REST controllers should extend Dokan base classes

How it compares

This skill enforces specific coding standards and architectural patterns for Dokan backend development, ensuring consistency and maintainability across the project.

Compared to similar skills

dokan-backend-dev side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
dokan-backend-dev (this skill)05moReviewIntermediate
laravel-specialist123moNo flagsIntermediate
developing-with-turbo-streams15moNo flagsIntermediate
payment-integration16moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

laravel-specialist

Jeffallan

Use when building Laravel 10+ applications requiring Eloquent ORM, API resources, or queue systems. Invoke for Laravel models, Livewire components, Sanctum authentication, Horizon queues.

1215

developing-with-turbo-streams

hotwired-laravel

Basics of developing with Turbo Streams in web applications. Activate when working on projects that utilize Turbo Streams for enhancing user experience through real-time updates, dynamic content changes, and partial page updates without full reloads.

15

payment-integration

mrgoonie

Integrate payments with SePay (VietQR), Polar, Stripe, Paddle (MoR subscriptions), Creem.io (licensing). Checkout, webhooks, subscriptions, QR codes, multi-provider orders.

13

developing-with-prism

prism-php

Guide for developing with Prism PHP package - a Laravel package for integrating LLMs. Activate or use when working with Prism features including text generation, structured output, embeddings, image generation, audio processing, streaming, tools/function calling, or any LLM provider integration (OpenAI, Anthropic, Gemini, Mistral, Groq, XAI, DeepSeek, OpenRouter, Ollama, VoyageAI, ElevenLabs). Activate for any Prism-related development tasks.

12

restapi-translations

mikopbx

Управление переводами REST API ключей (rest_*) для MikoPBX. Автоматически находит отсутствующие русские ключи в RestApi.php и синхронизирует их с исходным кодом. Использовать при проверке переводов API, после добавления новых endpoints или перед релизом.

11

moodle-external-api-development

davila7

Create custom external web service APIs for Moodle LMS. Use when implementing web services for course management, user tracking, quiz operations, or custom plugin functionality. Covers parameter validation, database operations, error handling, service registration, and Moodle coding standards.

10

Search skills

Search the agent skills registry