2026年8月1日
2026年8月1日
WordPressのWooCommerce商品タイプをカスタマイズする方法
はじめに
「WooCommerceに「サブスクリプション商品」や「予約商品」など独自の商品タイプを追加したい」「商品データタブに専用フィールドを追加したい」「特定の商品タイプだけの購入フローを実装したい」——WC_Productを継承してカスタム商品タイプを実装できます。
症状・原因
WooCommerceのデフォルト商品タイプ(シンプル・バリアブル・グループ化・外部)では表現できない商品形態が必要な場合、カスタム商品タイプを実装します。サブスクリプション・デジタルコンテンツ・予約商品などが代表例です。
解決手順
ステップ1:WC_Productを継承したクラスを作成する
// includes/class-wc-product-subscription.php
if ( ! defined( 'ABSPATH' ) ) exit;
class WC_Product_Subscription extends WC_Product {
// 商品タイプ名(クラス名から自動導出: wc-product-{type})
public string $product_type = 'subscription';
public function __construct( $product ) {
$this->supports[] = 'ajax_add_to_cart';
parent::__construct( $product );
}
// 商品タイプを返す
public function get_type(): string {
return 'subscription';
}
// サブスクリプション固有のゲッター
public function get_subscription_period(): string {
return $this->get_meta( '_subscription_period', true ) ?: 'month';
}
public function get_subscription_length(): int {
return (int) $this->get_meta( '_subscription_length', true );
}
public function get_subscription_price(): float {
return (float) $this->get_meta( '_subscription_price', true );
}
// サブスクリプション固有のセッター
public function set_subscription_period( string $period ): void {
$allowed = [ 'day', 'week', 'month', 'year' ];
$this->update_meta_data(
'_subscription_period',
in_array( $period, $allowed, true ) ? $period : 'month'
);
}
public function set_subscription_length( int $length ): void {
$this->update_meta_data( '_subscription_length', max( 0, $length ) );
}
public function set_subscription_price( float $price ): void {
$this->update_meta_data( '_subscription_price', wc_format_decimal( $price ) );
}
// 価格HTML(フロントエンドに表示する価格)
public function get_price_html( string $price = '' ): string {
$period = $this->get_subscription_period();
$label = [ 'day' => '日', 'week' => '週', 'month' => '月', 'year' => '年' ];
$price_html = wc_price( $this->get_subscription_price() );
return sprintf( '%s / %s', $price_html, $label[ $period ] ?? '月' );
}
}
ステップ2:商品タイプをWooCommerceに登録する
// my-subscription-plugin.php: プラグインのメインファイル
// クラスファイルを読み込む
add_action( 'plugins_loaded', function(): void {
if ( ! class_exists( 'WC_Product' ) ) {
return;
}
require_once plugin_dir_path( __FILE__ ) . 'includes/class-wc-product-subscription.php';
} );
// 商品タイプとしてWooCommerceに登録
add_filter( 'product_type_selector', function( array $types ): array {
$types['subscription'] = 'サブスクリプション';
return $types;
} );
// WC_Productクラスのオートロードに登録
add_filter( 'woocommerce_product_class', function( string $classname, string $product_type ): string {
if ( 'subscription' === $product_type ) {
return 'WC_Product_Subscription';
}
return $classname;
}, 10, 2 );
ステップ3:商品データタブとフィールドを追加する
// functions.php: 商品データパネルにサブスクリプションタブを追加
// 商品データタブを追加
add_filter( 'woocommerce_product_data_tabs', function( array $tabs ): array {
$tabs['subscription'] = [
'label' => 'サブスクリプション',
'target' => 'subscription_product_data',
'class' => [ 'show_if_subscription' ], // このタブを表示するクラス
'priority' => 21,
];
return $tabs;
} );
// 商品データパネルのHTMLを出力
add_action( 'woocommerce_product_data_panels', function(): void {
global $post;
$product = wc_get_product( $post->ID );
if ( ! $product instanceof WC_Product_Subscription ) {
$product = null;
}
?>
<div id="subscription_product_data" class="panel woocommerce_options_panel">
<div class="options_group">
<?php
woocommerce_wp_text_input( [
'id' => '_subscription_price',
'label' => 'サブスクリプション価格(¥)',
'value' => $product ? $product->get_subscription_price() : '',
'type' => 'number',
'custom_attributes' => [ 'min' => 0, 'step' => 1 ],
] );
woocommerce_wp_select( [
'id' => '_subscription_period',
'label' => '請求サイクル',
'value' => $product ? $product->get_subscription_period() : 'month',
'options' => [
'day' => '毎日',
'week' => '毎週',
'month' => '毎月',
'year' => '毎年',
],
] );
woocommerce_wp_text_input( [
'id' => '_subscription_length',
'label' => '契約期間(0=無期限)',
'value' => $product ? $product->get_subscription_length() : 0,
'type' => 'number',
'custom_attributes' => [ 'min' => 0, 'step' => 1 ],
] );
?>
</div>
</div>
<?php
} );
// フィールドの保存
add_action( 'woocommerce_process_product_meta', function( int $post_id ): void {
$product = wc_get_product( $post_id );
if ( ! $product instanceof WC_Product_Subscription ) {
return;
}
if ( isset( $_POST['_subscription_price'] ) ) {
$product->set_subscription_price( (float) wc_clean( $_POST['_subscription_price'] ) );
}
if ( isset( $_POST['_subscription_period'] ) ) {
$product->set_subscription_period( wc_clean( $_POST['_subscription_period'] ) );
}
if ( isset( $_POST['_subscription_length'] ) ) {
$product->set_subscription_length( (int) wc_clean( $_POST['_subscription_length'] ) );
}
$product->save();
} );
ステップ4:フロントエンドの表示とカートへの追加
// functions.php: サブスクリプション商品のカート追加をカスタマイズ
// カートに追加するときのバリデーション
add_filter( 'woocommerce_add_to_cart_validation', function(
bool $passed, int $product_id, int $quantity
): bool {
$product = wc_get_product( $product_id );
if ( ! $product instanceof WC_Product_Subscription ) {
return $passed;
}
// サブスクリプションはカートに1つだけ
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['product_id'] === $product_id ) {
wc_add_notice( 'このサブスクリプションはすでにカートに入っています。', 'error' );
return false;
}
}
return $passed;
}, 10, 3 );
// カートアイテムの価格を設定
add_action( 'woocommerce_before_calculate_totals', function( WC_Cart $cart ): void {
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
if ( $product instanceof WC_Product_Subscription ) {
$product->set_price( $product->get_subscription_price() );
}
}
} );
ステップ5:JavaScriptで商品タイプ別の表示制御
// admin/js/product-type.js: 商品タイプ変更時の表示制御
jQuery( function( $ ) {
// 商品タイプ切り替え時にサブスクリプション用フィールドを表示/非表示
$( '#product-type' ).on( 'change', function() {
var type = $( this ).val();
if ( type === 'subscription' ) {
$( '.show_if_subscription' ).show();
$( '.hide_if_subscription' ).hide();
// 通常価格フィールドを非表示
$( '._regular_price_field' ).hide();
$( '._sale_price_field' ).hide();
} else {
$( '.show_if_subscription' ).hide();
}
} ).trigger( 'change' );
} );
注意事項
product_typeプロパティ(public string $product_type = 'subscription')はクラス定義と一致させる必要があります。これがWooCommerceの商品タイプ検出に使用されます。- カスタム商品タイプのカートへの追加・決済処理は
woocommerce_before_calculate_totalsやwoocommerce_checkout_order_processedフックで制御できます。本格的なサブスクリプション機能にはWooCommerce Subscriptionsプラグインの使用を検討してください。 woocommerce_product_classフィルターはWooCommerce 3.0以降で使用できます。
まとめ
WooCommerceカスタム商品タイプの実装は「WC_Productを継承したクラスを作成→get_type()で商品タイプ名を返す→product_type_selectorフィルターで商品タイプドロップダウンに追加→woocommerce_product_classフィルターでクラスをマッピング→woocommerce_product_data_tabs/panelsフックで管理画面タブを追加→woocommerce_process_product_metaで保存」の流れで整備します。関連記事:WordPressのWooCommerceチェックアウトをカスタマイズする方法、WordPressでWooCommerceカスタム決済ゲートウェイを実装する方法。