Building Custom Integrations

Extend WP Sell Services with custom e-commerce platforms, payment gateways, REST API controllers, and more. This guide documents the actual interfaces and extension patterns available in the plugin source code.

Extension Architecture

WP Sell Services provides six contract interfaces in src/Integrations/Contracts/ and several filter-based registration points. The free version ships with standalone checkout, Stripe, and PayPal. The Pro version adds WooCommerce, EDD, FluentCart, and Razorpay.

Extension Type Interface/Filter Free Pro
E-commerce Platform EcommerceAdapterInterface Standalone (built-in) WooCommerce, EDD, FluentCart [PRO]
Payment Gateway PaymentGatewayInterface Stripe, PayPal, Offline Razorpay [PRO]
Storage Provider wpss_storage_providers Local uploads S3, GCS, DigitalOcean Spaces [PRO]
Email Provider wpss_email_providers WordPress mail SendGrid, Mailgun, SES
REST API Controller wpss_api_controllers 23 controllers Additional endpoints
Analytics Widget wpss_analytics_widgets Basic stats Revenue, conversion, vendor analytics [PRO]

E-Commerce Adapters

EcommerceAdapterInterface

Located at src/Integrations/Contracts/EcommerceAdapterInterface.php. All e-commerce integrations must implement this interface, which delegates to four specialized providers.

interface EcommerceAdapterInterface {
    public function get_id(): string;
    public function get_name(): string;
    public function is_active(): bool;
    public function init(): void;
    public function supports_feature( string $feature ): bool;
    public function get_order_provider(): OrderProviderInterface;
    public function get_product_provider(): ProductProviderInterface;
    public function get_checkout_provider(): CheckoutProviderInterface;
    public function get_account_provider(): AccountProviderInterface;
}

Provider Interfaces

OrderProviderInterface (src/Integrations/Contracts/OrderProviderInterface.php) -- Handles order data retrieval: get_order(), get_order_item(), get_customer_orders(), get_vendor_orders(), has_service_items(), get_service_items(), update_item_meta(), get_item_meta(), get_customer_data(), handle_order_complete().

ProductProviderInterface (src/Integrations/Contracts/ProductProviderInterface.php) -- Handles service-to-product mapping: is_service_product(), get_service(), get_service_vendors(), get_requirements(), get_delivery_time(), set_service_type(), add_service_type_option(), save_service_meta(), sync_with_service().

CheckoutProviderInterface (src/Integrations/Contracts/CheckoutProviderInterface.php) -- Handles cart and checkout: add_cart_item_data(), validate_add_to_cart(), get_checkout_url(), cart_has_services(), get_cart_services(), process_checkout(), get_thankyou_redirect(), filter_quantity_max().

AccountProviderInterface (src/Integrations/Contracts/AccountProviderInterface.php) -- Handles user account integration: add_menu_items(), register_endpoints(), get_account_url(), get_orders_url(), get_vendor_dashboard_url(), render_orders_endpoint(), render_services_endpoint(), render_notifications_endpoint(), can_access_vendor_dashboard(), get_login_url(), get_register_url().

Creating a Custom Adapter

<?php
namespace MyPlugin;

use WPSellServices\Integrations\Contracts\EcommerceAdapterInterface;

class CustomPlatformAdapter implements EcommerceAdapterInterface {
    public function get_id(): string { return 'custom_platform'; }
    public function get_name(): string { return 'Custom Platform'; }
    public function is_active(): bool { return class_exists( 'CustomPlatform' ); }
    public function init(): void { /* Register platform hooks */ }
    public function supports_feature( string $feature ): bool {
        return in_array( $feature, [ 'checkout', 'orders' ], true );
    }
    public function get_order_provider(): OrderProviderInterface { return new CustomOrderProvider(); }
    public function get_product_provider(): ProductProviderInterface { return new CustomProductProvider(); }
    public function get_checkout_provider(): CheckoutProviderInterface { return new CustomCheckoutProvider(); }
    public function get_account_provider(): AccountProviderInterface { return new CustomAccountProvider(); }
}

// Register via filter
add_filter( 'wpss_ecommerce_adapters', function( $adapters ) {
    $adapters['custom_platform'] = new \MyPlugin\CustomPlatformAdapter();
    return $adapters;
} );

Adapter Selection Logic

The IntegrationManager (src/Integrations/IntegrationManager.php) selects the active adapter:

  1. Reads ecommerce_platform from wpss_general settings
  2. If set to a specific adapter ID and that adapter's is_active() is true, uses it
  3. If set to 'auto' (default), iterates all registered adapters and uses the first active one
  4. After selection, calls $adapter->init() and fires wpss_adapter_initialized

Payment Gateways

PaymentGatewayInterface

Located at src/Integrations/Contracts/PaymentGatewayInterface.php. Used for standalone payment processing without an e-commerce platform.

interface PaymentGatewayInterface {
    public function get_id(): string;
    public function get_name(): string;
    public function get_description(): string;
    public function is_enabled(): bool;
    public function supports_currency( string $currency ): bool;
    public function init(): void;
    public function create_payment( float $amount, string $currency, array $metadata = [] ): array;
    public function process_payment( string $payment_id ): array;
    public function process_refund( string $transaction_id, ?float $amount = null, string $reason = '' ): array;
    public function handle_webhook( array $payload ): array;
    public function get_settings_fields(): array;
    public function render_payment_form( float $amount, string $currency, int $order_id ): string;
}

Creating a Custom Gateway

The plugin includes a reference implementation at src/Integrations/Gateways/TestGateway.php (debug-only, auto-completes payments). Register your gateway via the wpss_payment_gateways filter (Plugin.php:813):

add_filter( 'wpss_payment_gateways', function( $gateways ) {
    $gateways['custom_pay'] = new \MyPlugin\CustomGateway();
    return $gateways;
} );

Key methods to implement:

  • create_payment() should return ['success' => true, 'id' => '...', 'client_secret' => '...']
  • process_payment() should return ['success' => true, 'transaction_id' => '...', 'status' => 'completed']
  • process_refund() should return ['success' => true, 'refund_id' => '...', 'status' => 'completed']
  • get_settings_fields() returns an array of field definitions (type, label)
  • render_payment_form() returns HTML for the payment form

The CheckoutIntent seam (gateway-agnostic)

Added in 1.3.0. Every purchase — pay an existing order, buy a multi-item cart, or buy a single service + add-ons — resolves to a single value object, CheckoutIntent, before any gateway is involved. This is the seam that lets Stripe, PayPal, Razorpay (Pro), and your custom gateway all charge the same way, and it guarantees the amount is server-computed, never trusted from the client.

The flow is always resolve → charge → settle:

use WPSellServices\Checkout\CheckoutIntentService;

$service = new CheckoutIntentService();

// 1. RESOLVE — the server computes the authoritative amount + currency from the
//    request. Returns a CheckoutIntent, or a WP_Error if the request is invalid.
$intent = $service->resolve( $request, $buyer_id );   // $request: service_id/package_id, or cart, or order_id
if ( is_wp_error( $intent ) ) {
    return $intent;
}

// $intent->amount / ->currency are authoritative — charge THIS, never a client value.

// 2. CHARGE — run your gateway with $intent->amount and $intent->currency.

// 3. SETTLE — record the completed charge; the plugin creates/links the order,
//    delivery deadline, commission split, and ledger entries.
$result = $service->settle( $intent, 'custom_pay', $transaction_id, $charged_amount, $charged_currency );

CheckoutIntent is built through three factories that mirror the three purchase kinds — CheckoutIntent::order(), ::cart(), ::single() — but you normally get one back from resolve() rather than constructing it yourself. Base currency stays authoritative throughout; the charged_currency you pass to settle() records what the gateway actually took.

REST API Controllers

Custom controllers extend RestController (src/API/RestController.php) which provides:

  • check_permissions( $request ) -- Verifies user is logged in (returns 401 if not)
  • check_admin_permissions( $request ) -- Verifies manage_options capability (returns 403 if not)
  • user_owns_resource( $resource_id, $resource_type ) -- Checks ownership for 'service' or 'order'
  • paginated_response( $items, $total, $page, $per_page ) -- Returns paginated response with X-WP-Total and X-WP-TotalPages headers
<?php
namespace MyPlugin;
use WPSellServices\API\RestController;

class CustomController extends RestController {
    protected $rest_base = 'custom';

    public function register_routes() {
        register_rest_route( $this->namespace, '/' . $this->rest_base, [
            [
                'methods'             => \WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_items' ],
                'permission_callback' => [ $this, 'check_permissions' ],
            ],
        ] );
    }

    public function get_items( \WP_REST_Request $request ): \WP_REST_Response {
        $items = []; // Your data retrieval logic
        return $this->paginated_response( $items, 0, 1, 10 );
    }
}

// Register the controller (filter at API.php:76)
add_filter( 'wpss_api_controllers', function( $controllers ) {
    $controllers[] = new \MyPlugin\CustomController();
    return $controllers;
} );

Provider Registration Filters [PRO]

// Storage providers (Plugin.php:837)
add_filter( 'wpss_storage_providers', function( $providers ) {
    $providers['custom_storage'] = new \MyPlugin\CustomStorageProvider();
    return $providers;
} );

// Email providers (Plugin.php:849)
add_filter( 'wpss_email_providers', function( $providers ) {
    $providers['custom_email'] = new \MyPlugin\CustomEmailProvider();
    return $providers;
} );

// Wallet providers (Plugin.php:825)
add_filter( 'wpss_wallet_providers', function( $providers ) {
    $providers['custom_wallet'] = new \MyPlugin\CustomWalletProvider();
    return $providers;
} );

// Analytics widgets (Plugin.php:861)
add_filter( 'wpss_analytics_widgets', function( $widgets ) {
    $widgets['custom_metric'] = new \MyPlugin\CustomAnalyticsWidget();
    return $widgets;
} );

Settings Tabs

Add custom tabs to admin settings using wpss_settings_tabs filter (Settings.php:161) and the dynamic wpss_settings_tab_{tab} action (Settings.php:985):

add_filter( 'wpss_settings_tabs', function( $tabs ) {
    $tabs['my_integration'] = 'My Integration';
    return $tabs;
} );

add_action( 'wpss_settings_tab_my_integration', function() {
    echo '<div class="wpss-settings-section"><h2>My Settings</h2>';
    // Your settings form here
    echo '</div>';
} );

Custom Field Types

Register custom field types for service requirements via the wpss_register_field_types action (FieldManager.php:59). Default types: Text, Textarea, Select, MultiSelect, Radio, Checkbox, FileUpload, Date, Number.

add_action( 'wpss_register_field_types', function( $manager ) {
    $manager->register( new \MyPlugin\ColorPickerField() );
} );

Gutenberg Blocks

Register custom blocks via wpss_blocks filter (BlocksManager.php:93):

add_filter( 'wpss_blocks', function( $blocks ) {
    $blocks[] = [
        'name' => 'wpss/custom-block',
        'args' => [ 'title' => 'Custom Block', 'category' => 'wpss', 'render_callback' => 'render_my_block' ],
    ];
    return $blocks;
} );

How Pro Extends Free

The Pro plugin hooks into wpss_loaded to register all extensions:

What Pro Changes Filter Free Default Pro Value
Gallery images wpss_service_max_gallery 4 -1 (unlimited)
Service extras wpss_service_max_extras 3 -1 (unlimited)
FAQ items wpss_service_max_faq 5 -1 (unlimited)
Video URLs wpss_service_max_videos 1 1 (Pro does not filter this)
Requirements wpss_service_max_requirements 5 -1 (unlimited)

Vendor Capabilities

The wpss_vendor role includes: wpss_vendor, wpss_manage_services, wpss_manage_orders, wpss_view_analytics, wpss_respond_to_requests, read, upload_files, edit_posts.

Related Documentation