2026年9月3日

2026年9月3日

WordPressのWooCommerceマルチベンダーマーケットプレイスを構築する方法

はじめに

AmazonマーケットプレイスやメルカリのようなマルチベンダーECサイトをWordPressとWooCommerceで構築できます。DokanやWC Vendorsというプラグインを使えば、複数の販売者がそれぞれの商品を出品・管理できるプラットフォームを比較的短期間で構築できます。本記事ではDokanを軸にベンダー登録フロー、手数料設定、ダッシュボードカスタマイズ、支払い管理まで実践的な実装方法を解説します。

症状・原因

  • WooCommerceで複数の販売者が独自の商品を登録・管理できる仕組みを作りたい
  • 各ベンダーの売上から自動的に手数料を引いた金額を支払いたいが仕組みが分からない
  • ベンダーダッシュボードのデザインをブランドに合わせてカスタマイズしたい

解決手順

ステップ1:DokanプラグインとWooCommerceのベンダーロールを設定する

# WP-CLIでDokanとWooCommerceをインストール
wp plugin install woocommerce --activate
wp plugin install dokan-lite --activate

# Dokanの設定
wp option set dokan_general '{
    "admin_access": "on",
    "seller_enable_terms_and_conditions": "on",
    "commission_type": "percentage",
    "admin_percentage": 10
}'
<?php
// Dokan有効化後にベンダーロールを確認・カスタマイズ
add_action( 'init', 'customize_vendor_role' );
function customize_vendor_role() {
    // 'seller'ロール(Dokanのデフォルトベンダーロール)を取得
    $seller_role = get_role( 'seller' );

    if ( ! $seller_role ) {
        return;
    }

    // ベンダーに許可する追加権限
    $seller_role->add_cap( 'read' );                     // ダッシュボードへのアクセス
    $seller_role->add_cap( 'upload_files' );             // メディアアップロード
    $seller_role->add_cap( 'edit_posts' );               // 商品編集
    $seller_role->add_cap( 'publish_posts' );            // 商品公開
    $seller_role->remove_cap( 'delete_published_posts' );// 公開済み商品の削除は禁止

    // ベンダーが編集できる最大価格を制限するカスタム設定
    add_filter( 'dokan_product_max_price', function( $max ) {
        if ( current_user_can( 'seller' ) ) {
            return 1000000; // 100万円まで
        }
        return $max;
    } );
}

// 新規ユーザー登録時にベンダー申請フォームを表示する
add_filter( 'dokan_seller_registration_required_fields', 'add_vendor_required_fields' );
function add_vendor_required_fields( $fields ) {
    $fields['company_name'] = array(
        'label'       => '会社名・店舗名',
        'required'    => true,
        'placeholder' => '例:山田商店',
    );
    $fields['business_type'] = array(
        'label'    => '事業種別',
        'required' => true,
        'type'     => 'select',
        'options'  => array(
            'individual' => '個人',
            'company'    => '法人',
        ),
    );
    return $fields;
}

ステップ2:ベンダー登録フローとショップ作成を実装する

<?php
// ベンダー登録後のウェルカムメールと初期設定
add_action( 'dokan_new_seller_created', 'welcome_new_vendor', 10, 2 );
function welcome_new_vendor( $seller_id, $dokan_settings ) {
    $user = get_user_by( 'id', $seller_id );

    // Dokanのショップ情報を設定
    dokan_update_seller_info( $seller_id, array(
        'payment'           => array(
            'paypal' => array( 'email' => $user->user_email ),
        ),
        'social'            => array(),
        'shop'              => array(
            'url'         => '', // ショップURLスラッグ
            'name'        => $user->display_name . 'のショップ',
            'is_autoload' => 'yes',
        ),
        'dokan_enable_store_seo' => 'on',
    ) );

    // ウェルカムメールを送信
    $subject = 'マーケットプレイスへのご登録ありがとうございます';
    $message = sprintf(
        "こんにちは %s さん\n\n出品者として承認されました。\n\n" .
        "ダッシュボード: %s\n\n" .
        "まず最初に商品を登録してみましょう!\n" .
        "ご不明な点があればサポートまでご連絡ください。",
        $user->display_name,
        dokan_get_navigation_url( 'dashboard' )
    );

    wp_mail( $user->user_email, $subject, $message );

    // 管理者にも通知
    wp_mail(
        get_option( 'admin_email' ),
        '新しいベンダーが登録されました: ' . $user->display_name,
        "ユーザーID: {$seller_id}\nメール: {$user->user_email}\nダッシュボード: " . admin_url( 'user-edit.php?user_id=' . $seller_id )
    );
}

// ベンダー承認(管理者が手動承認する場合)
add_action( 'dokan_seller_enabled', 'on_vendor_approved', 10, 2 );
function on_vendor_approved( $seller_id, $enabled ) {
    if ( $enabled ) {
        $user = get_user_by( 'id', $seller_id );
        wp_mail(
            $user->user_email,
            '出品者アカウントが承認されました',
            "おめでとうございます!出品者アカウントが承認されました。\n商品の出品を開始できます。\n\n" . dokan_get_navigation_url()
        );
    }
}

ステップ3:手数料の設定(パーセンテージ・固定費)

<?php
// グローバル手数料設定(Dokan設定画面でも設定可能)
add_filter( 'dokan_get_admin_commission', 'custom_commission_rate', 10, 3 );
function custom_commission_rate( $commission, $seller_id, $product_id ) {
    // カテゴリ別手数料
    $categories = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'slugs' ) );

    if ( in_array( 'electronics', $categories, true ) ) {
        // 電子機器は手数料8%
        return array(
            'type'  => 'percentage',
            'value' => 8,
        );
    }

    if ( in_array( 'fashion', $categories, true ) ) {
        // ファッションは手数料15%
        return array(
            'type'  => 'percentage',
            'value' => 15,
        );
    }

    // VIPベンダーは手数料5%(ベンダーメタで設定)
    $vendor_tier = get_user_meta( $seller_id, 'vendor_tier', true );
    if ( 'vip' === $vendor_tier ) {
        return array(
            'type'  => 'percentage',
            'value' => 5,
        );
    }

    // デフォルト: パーセンテージ + 固定費
    return array(
        'type'       => 'percentage',
        'value'      => 10,
        'fixed'      => 100, // 固定100円
        'type_fixed' => 'flat', // 注文ごとに固定費を加算
    );
}

// 手数料計算ロジック(参考)
function calculate_vendor_earning( $order_id ) {
    $order         = wc_get_order( $order_id );
    $order_total   = floatval( $order->get_total() );
    $commission    = dokan_get_order_net_amount( $order_id ); // プラットフォーム手数料
    $vendor_earning = $order_total - $commission;

    return array(
        'order_total'    => $order_total,
        'commission'     => $commission,
        'vendor_earning' => $vendor_earning,
    );
}

ステップ4:ベンダーダッシュボードをショートコードでカスタマイズする

<?php
// Dokanダッシュボードにカスタムタブを追加
add_filter( 'dokan_get_dashboard_nav', 'add_custom_dashboard_tab' );
function add_custom_dashboard_tab( $tabs ) {
    $tabs['analytics'] = array(
        'title' => '売上分析',
        'icon'  => '<i class="fas fa-chart-bar"></i>',
        'url'   => dokan_get_navigation_url( 'analytics' ),
        'pos'   => 60, // メニューの順序
    );

    $tabs['inventory'] = array(
        'title' => '在庫管理',
        'icon'  => '<i class="fas fa-boxes"></i>',
        'url'   => dokan_get_navigation_url( 'inventory' ),
        'pos'   => 70,
    );

    return $tabs;
}

// カスタムダッシュボードタブのコンテンツ
add_action( 'dokan_dashboard_content', 'render_analytics_dashboard' );
function render_analytics_dashboard() {
    if ( ! dokan_is_seller_dashboard() ) {
        return;
    }

    $current_tab = get_query_var( 'custom_tab' ) ?: 'analytics';

    if ( 'analytics' !== $current_tab ) {
        return;
    }

    $seller_id = get_current_user_id();

    // 過去30日間の売上データを取得
    $sales_data = dokan_get_seller_earnings(
        $seller_id,
        array(
            'from' => date( 'Y-m-d', strtotime( '-30 days' ) ),
            'to'   => date( 'Y-m-d' ),
        )
    );

    // 商品別売上ランキング
    $top_products = wc_get_orders( array(
        'meta_key'    => '_dokan_vendor_id',
        'meta_value'  => $seller_id,
        'status'      => 'completed',
        'limit'       => 10,
        'date_after'  => '-30 days',
        'return'      => 'ids',
    ) );

    ?>
    <div class="dokan-dash-header">
        <h2>売上分析(過去30日間)</h2>
    </div>
    <div class="analytics-grid" style="display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin:20px 0;">
        <div class="stat-card" style="background:#fff;padding:20px;border-radius:8px;text-align:center;">
            <h3 style="color:#0073aa;">¥<?php echo number_format( $sales_data['total_earning'] ?? 0 ); ?></h3>
            <p>売上合計</p>
        </div>
        <div class="stat-card" style="background:#fff;padding:20px;border-radius:8px;text-align:center;">
            <h3 style="color:#00a32a;"><?php echo intval( $sales_data['orders_count'] ?? 0 ); ?>件</h3>
            <p>注文数</p>
        </div>
        <div class="stat-card" style="background:#fff;padding:20px;border-radius:8px;text-align:center;">
            <h3 style="color:#f0b849;">¥<?php echo number_format( $sales_data['avg_order'] ?? 0 ); ?></h3>
            <p>平均注文単価</p>
        </div>
    </div>
    <?php
}

ステップ5:支払い管理(手動振込 vs Stripe Connect自動分配)

<?php
// 方法1: 手動振込の管理(管理者がCSVエクスポートして振込)
add_action( 'admin_post_export_vendor_payouts', 'export_vendor_payouts_csv' );
function export_vendor_payouts_csv() {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( '権限がありません' );
    }

    check_admin_referer( 'export_payouts' );

    // 未払いの売上を取得
    $unpaid_earnings = dokan_get_unpaid_earnings( array(
        'threshold' => 1000, // 1000円以上のみ振込対象
    ) );

    // CSVヘッダー
    header( 'Content-Type: text/csv; charset=UTF-8' );
    header( 'Content-Disposition: attachment; filename="payouts-' . date( 'Y-m-d' ) . '.csv"' );

    $output = fopen( 'php://output', 'w' );
    // UTF-8 BOM(Excelで文字化けしないように)
    fputs( $output, "\xEF\xBB\xBF" );

    fputcsv( $output, array( 'ベンダーID', '店舗名', 'メール', '振込金額', '銀行口座', '確認' ) );

    foreach ( $unpaid_earnings as $seller_id => $amount ) {
        $seller  = get_user_by( 'id', $seller_id );
        $bank    = get_user_meta( $seller_id, 'dokan_payment_bank', true );
        fputcsv( $output, array(
            $seller_id,
            dokan_get_store_info( $seller_id )['store_name'] ?? $seller->display_name,
            $seller->user_email,
            intval( $amount ),
            $bank['ac_number'] ?? '未登録',
            '', // 振込確認チェック欄
        ) );
    }

    fclose( $output );
    exit;
}

// 方法2: Stripe Connectによる自動分配設定
// Dokan ProのStripe Connectアドオンを使う場合のフック例
add_action( 'dokan_stripe_connect_after_transfer', 'log_stripe_transfer', 10, 3 );
function log_stripe_transfer( $transfer_id, $seller_id, $amount ) {
    // Stripe送金のログを保存
    $log_entry = array(
        'transfer_id' => $transfer_id,
        'seller_id'   => $seller_id,
        'amount'      => $amount,
        'date'        => current_time( 'mysql' ),
        'status'      => 'completed',
    );

    // カスタムテーブルにログを記録
    global $wpdb;
    $wpdb->insert(
        $wpdb->prefix . 'dokan_transfer_log',
        $log_entry,
        array( '%s', '%d', '%d', '%s', '%s' )
    );

    error_log( sprintf( 'Stripe Transfer: %s - Seller: %d - Amount: ¥%d', $transfer_id, $seller_id, $amount ) );
}

注意事項

  • 特定商取引法: マルチベンダーマーケットプレイスでは各ベンダーの特定商取引法に基づく表記を商品ページに表示する義務があります。Dokanのベンダー情報設定でこれを実装してください
  • 消費税処理: 各ベンダーの消費税登録状況(インボイス制度)を確認し、税込・税抜の表示と計算が正確であることを確認してください
  • Stripe Connectの審査: Stripe ConnectのプラットフォームアカウントはStripeによる審査が必要です。事業内容を正確に申告し、審査完了まで数日かかることを考慮してください
  • 解約・退会処理: ベンダーが退会する際に未発送の注文・未払いの売上の処理ルールをあらかじめ利用規約で定めておく必要があります

まとめ

WordPressのWooCommerceマルチベンダーマーケットプレイスはDokanまたはWC Vendorsで実現できます。ベンダー登録フロー・カテゴリ別手数料・カスタムダッシュボード・CSVまたはStripe Connectによる支払いと、一連のシステムを段階的に実装することで完全なマーケットプレイスを構築できます。関連記事:WordPressのWooCommerceを使った物販サイト構築

お気軽にご相談ください

お見積りへ お問い合わせへ