2026年7月2日

2026年7月2日

WooCommerceの注文ステータスをカスタマイズ・修正する方法

はじめに

WooCommerceの注文ステータスが自動で変わらない・カスタムステータスを追加したい・特定のステータス変更時に処理を実行したい問題は、ステータスの登録方法・フックのタイミング・権限設定が原因です。

症状・原因

  • 注文が「保留中」から「処理中」に自動で変わらない
  • 独自の注文ステータス(例:「梱包中」)を追加したい
  • ステータス変更時に自動でメールを送りたい
  • 特定のステータスから他のステータスへの変更を制限したい

解決手順

ステップ1:注文ステータスの現状を確認する

# 現在の注文ステータス一覧を確認
wp eval "
\$statuses = wc_get_order_statuses();
foreach (\$statuses as \$slug => \$label) {
    printf('%s: %s' . PHP_EOL, \$slug, \$label);
}
"

# 特定の注文のステータス変更履歴を確認
wp eval "
\$order = wc_get_order(123);
foreach (\$order->get_notes() as \$note) {
    if (str_contains(\$note->comment_content, 'ステータス') || str_contains(\$note->comment_content, 'status')) {
        echo \$note->comment_date . ': ' . \$note->comment_content . PHP_EOL;
    }
}
"

# 特定ステータスの注文数を確認
wp eval "
\$statuses = ['pending', 'processing', 'on-hold', 'completed', 'cancelled', 'refunded', 'failed'];
foreach (\$statuses as \$status) {
    \$orders = wc_get_orders(['status' => \$status, 'limit' => -1]);
    printf('%s: %d件' . PHP_EOL, \$status, count(\$orders));
}
"

ステップ2:カスタム注文ステータスを追加する

// functions.php: カスタム注文ステータスを登録

// ① WordPress のポストステータスとして登録
add_action('init', function(): void {
    register_post_status('wc-packing', [
        'label'                     => '梱包中',
        'public'                    => true,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'exclude_from_search'       => false,
        'label_count'               => _n_noop('梱包中 <span class="count">(%s)</span>', '梱包中 <span class="count">(%s)</span>'),
    ]);

    register_post_status('wc-shipped', [
        'label'                     => '発送済み',
        'public'                    => true,
        'show_in_admin_all_list'    => true,
        'show_in_admin_status_list' => true,
        'exclude_from_search'       => false,
        'label_count'               => _n_noop('発送済み <span class="count">(%s)</span>', '発送済み <span class="count">(%s)</span>'),
    ]);
});

// ② WooCommerceのステータス一覧に追加
add_filter('woocommerce_order_statuses', function(array $order_statuses): array {
    $new_statuses = [];
    foreach ($order_statuses as $key => $status) {
        $new_statuses[$key] = $status;
        // 「処理中」の後に「梱包中」「発送済み」を挿入
        if ($key === 'wc-processing') {
            $new_statuses['wc-packing'] = '梱包中';
            $new_statuses['wc-shipped'] = '発送済み';
        }
    }
    return $new_statuses;
});

// ③ カスタムステータスの色をアイコン付きで設定
add_action('admin_head', function(): void {
    echo '<style>
        .order-status.status-packing { background: #f0e6ff; color: #7c3aed; }
        .order-status.status-shipped { background: #d1fae5; color: #059669; }
        mark.order-status.status-packing::before { content: "\\f526"; }
        mark.order-status.status-shipped::after { content: " ✈"; }
    </style>';
});

ステップ3:ステータス変更時に処理を実行する

// functions.php: 注文ステータス変更時のフック

// ① 特定のステータスに変わったときに処理
add_action('woocommerce_order_status_shipped', function(int $order_id): void {
    $order = wc_get_order($order_id);
    if (!$order) return;

    // 追跡番号メタを確認
    $tracking = $order->get_meta('_tracking_number');

    // 顧客に発送完了メールを送信
    WC()->mailer()->emails['WC_Email_Customer_Completed_Order']->trigger($order_id);

    // 注文にメモを追加
    $order->add_order_note(
        sprintf('発送済みに変更しました。追跡番号: %s', $tracking ?: '未設定'),
        true // 顧客に表示
    );
});

// ② ステータスが「from」から「to」に変わったとき
add_action('woocommerce_order_status_changed', function(int $order_id, string $from, string $to): void {
    if ($from === 'processing' && $to === 'packing') {
        // 倉庫システムに通知
        $order = wc_get_order($order_id);
        wp_remote_post('https://warehouse.example.com/api/orders', [
            'body' => json_encode([
                'order_id' => $order_id,
                'items'    => array_map(fn($item) => [
                    'sku' => $item->get_product()->get_sku(),
                    'qty' => $item->get_quantity(),
                ], array_values($order->get_items())),
            ]),
            'headers' => ['Content-Type' => 'application/json'],
        ]);
    }
}, 10, 3);

// ③ カスタムステータスでも在庫を減らす
add_filter('woocommerce_payment_complete_order_status', function(string $status, int $order_id): string {
    return 'packing'; // 支払い完了後は「梱包中」に
}, 10, 2);

ステップ4:注文ステータスをプログラムで変更する

// functions.php: 注文ステータスを一括変更

// ① 単一注文のステータスを変更
function update_order_status(int $order_id, string $new_status, string $note = ''): bool {
    $order = wc_get_order($order_id);
    if (!$order) {
        return false;
    }
    $order->update_status($new_status, $note, true);
    return true;
}

// ② 複数注文を一括でステータス変更
function bulk_update_order_status(array $order_ids, string $new_status): int {
    $updated = 0;
    foreach ($order_ids as $order_id) {
        $order = wc_get_order($order_id);
        if ($order && $order->update_status($new_status)) {
            $updated++;
        }
    }
    return $updated;
}
# 特定条件の注文を一括でステータス変更
wp eval "
// 7日以上「保留中」の注文をキャンセルに
\$old_orders = wc_get_orders([
    'status'       => 'pending',
    'date_before'  => date('Y-m-d', strtotime('-7 days')),
    'limit'        => 50,
]);
foreach (\$old_orders as \$order) {
    \$order->update_status('cancelled', '7日以上保留のため自動キャンセル');
}
echo count(\$old_orders) . '件をキャンセルしました';
"

ステップ5:カスタムステータス用のメールを設定する

// functions.php: カスタムステータス用のWooCommerceメールを登録

add_filter('woocommerce_email_classes', function(array $email_classes): array {
    require_once get_stylesheet_directory() . '/includes/class-wc-email-shipped.php';
    $email_classes['WC_Email_Customer_Shipped'] = new WC_Email_Customer_Shipped();
    return $email_classes;
});

// includes/class-wc-email-shipped.php
class WC_Email_Customer_Shipped extends WC_Email {
    public function __construct() {
        $this->id             = 'customer_shipped';
        $this->title          = '発送済み通知';
        $this->description    = '注文が発送済みになった時に顧客へ送信';
        $this->heading        = 'ご注文が発送されました';
        $this->subject        = '【発送完了】{site_title} ご注文 #{order_number}';
        $this->template_html  = 'emails/customer-shipped-order.html';
        $this->template_plain = 'emails/plain/customer-shipped-order.php';
        $this->placeholders   = [
            '{site_title}'   => $this->get_blogname(),
            '{order_number}' => '',
        ];
        $this->trigger_on = ['shipped'];
        add_action('woocommerce_order_status_shipped_notification', [$this, 'trigger'], 10, 2);
        parent::__construct();
    }

    public function trigger(int $order_id, ?WC_Order $order = null): void {
        if (!$order) {
            $order = wc_get_order($order_id);
        }
        $this->recipient = $order->get_billing_email();
        $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), []);
    }
}

注意事項

  • カスタムステータスのスラッグはwc-プレフィックスが必要です(例:wc-packing)。register_post_status()に渡すときもwc-packingで登録し、update_status()に渡すときはpackingwc-なし)で渡します
  • woocommerce_order_status_{status}フックの{status}部分はwc-プレフィックスなしのステータス名です(例:woocommerce_order_status_shipped
  • カスタムステータスに対応したメールクラスを作成する場合、テンプレートファイルもテーマのwoocommerce/emails/ディレクトリに用意する必要があります

まとめ

WooCommerce注文ステータスのカスタマイズは①wc_get_order_statuses()で現状を確認、②register_post_status('wc-packing', [...])で独自ステータスを登録しwoocommerce_order_statusesフィルターで一覧に追加、③woocommerce_order_status_shippedフックでステータス変更時の処理(メール送信・外部API連携)を実装、④order->update_status()で個別・一括ステータス変更を実行、⑤woocommerce_email_classesフィルターでカスタムステータス用のメールクラスを登録します。

お気軽にご相談ください

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