Plugin Directory

Changeset 2414739


Ignore:
Timestamp:
11/08/2020 01:45:35 PM (4 years ago)
Author:
growniche
Message:

定期支払に対応

Location:
simple-stripe-checkout/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • simple-stripe-checkout/trunk/readme.txt

    r2285735 r2414739  
    33Tags: simple, stripe, checkout
    44Requires at least: 4.9.13
    5 Tested up to: 5.4
    6 Stable tag: 1.0.4
     5Tested up to: 5.5
     6Stable tag: 1.1.0
    77License: GPL v3 or later
    88License URI: http://www.gnu.org/licenses/gpl-3.0.html
     
    4242= 1.0.4 =
    4343* 2020-04-10 軽微な修正
     44= 1.1.0 =
     45* 2020-11-08 定期支払に対応
  • simple-stripe-checkout/trunk/simple-stripe-checkout.php

    r2280361 r2414739  
    55  Plugin URI: https://s-page.biz/plugins/simple-stripe-checkout/
    66  Description: 決済プラットフォーム「Stripe」の連携プラグイン
    7   Version: 1.0.4
     7  Version: 1.1.0
    88  Author: growniche
    99  Author URI: https://www.growniche.co.jp/
     
    1616register_activation_hook(__FILE__, function() {
    1717
    18     // optionsテーブルに決済完了ページのSLUGが未登録の場合
    19     if (strlen(get_option(SimpleStripeCheckout::OPTION_KEY__CHECKEDOUT_PAGE_SLUG )) === 0) {
     18    // 固定ページ「決済完了」が未登録の場合
     19    if (!get_page_by_path(SimpleStripeCheckout::SLUG__CHECKEDOUT)) {
    2020        // 決済完了の固定ページを作成
    2121        $page_id = wp_insert_post(array(
     
    3131            'post_type' => 'page'
    3232        ));
    33         $pages = get_pages('include=' . $page_id);
    34         if (count($pages) > 0) {
    35             // 決済完了ページのSLUGをoptionsテーブルに保存
    36             update_option(SimpleStripeCheckout::OPTION_KEY__CHECKEDOUT_PAGE_SLUG, $pages[0]->post_name);
    37         }
    38     }
    39 
    40     // optionsテーブルにキャンセル完了了ページのSLUGが未登録の場合
    41     if (strlen(get_option(SimpleStripeCheckout::OPTION_KEY__CANCEL_PAGE_SLUG)) === 0) {
     33        get_pages('include=' . $page_id);
     34    }
     35
     36    // 固定ページ「キャンセル完了」が未登録の場合
     37    if (!get_page_by_path(SimpleStripeCheckout::SLUG__CANCEL)) {
    4238        // キャンセル完了の固定ページを作成
    4339        $page_id = wp_insert_post(array(
     
    5349            'post_type' => 'page'
    5450        ));
    55         $pages = get_pages('include=' . $page_id);
    56         if (count($pages) > 0) {
    57             // キャンセル完了ページのSLUGをoptionsテーブルに保存
    58             update_option(SimpleStripeCheckout::OPTION_KEY__CANCEL_PAGE_SLUG, $pages[0]->post_name);
    59         }
    60     }
    61 
    62     // optionsテーブルに決済確定完了ページのSLUGが未登録の場合
    63     if (strlen(get_option(SimpleStripeCheckout::OPTION_KEY__CAPTURE_COMPLETE_PAGE_SLUG)) === 0) {
     51        get_pages('include=' . $page_id);
     52    }
     53
     54    // 固定ページ「決済確定完了」が未登録の場合
     55    if (!get_page_by_path(SimpleStripeCheckout::SLUG__CAPTURE_COMPLETE)) {
    6456        // 決済確定完了の固定ページを作成
    6557        $page_id = wp_insert_post(array(
     
    7567            'post_type' => 'page'
    7668        ));
    77         $pages = get_pages('include=' . $page_id);
    78         if (count($pages) > 0) {
    79             // 決済確定完了ページのSLUGをoptionsテーブルに保存
    80             update_option(SimpleStripeCheckout::OPTION_KEY__CAPTURE_COMPLETE_PAGE_SLUG, $pages[0]->post_name);
    81         }
     69        get_pages('include=' . $page_id);
     70    }
     71
     72    // 固定ページ「定期支払キャンセル完了」が未登録の場合
     73    if (!get_page_by_path(SimpleStripeCheckout::SLUG__CANCELED_SUBSCRIPTION)) {
     74        // 定期支払キャンセル完了の固定ページを作成
     75        $page_id = wp_insert_post(array(
     76            'post_name' => SimpleStripeCheckout::SLUG__CANCELED_SUBSCRIPTION,
     77            'post_author' => 1,
     78            'post_title' => '定期支払キャンセル完了',
     79            'post_content' => 'ご登録いただいていた定期支払いをキャンセルしました。
     80ご利用ありがとうございました。
     81
     82[gssc-product-name]',
     83            'post_parent' => 0,
     84            'post_status' => 'publish',
     85            'post_type' => 'page'
     86        ));
     87        get_pages('include=' . $page_id);
    8288    }
    8389
     
    122128     */
    123129    public $button_name;
     130
     131    /**
     132     * プロパティ:商品請求タイミング
     133     */
     134    public $billing_timing;
     135
     136    /**
     137     * プロパティ:商品請求間隔
     138     */
     139    public $billing_frequency;
     140
     141    /**
     142     * プロパティ:商品無料トライアル
     143     */
     144    public $free_trial_days;
    124145}
    125146
     
    184205                    strpos($item->name, $s) ||
    185206                    strpos($item->currency, $s) ||
    186                     strpos($item->button_name, $s);
     207                    strpos($item->button_name, $s) ||
     208                    strpos($item->billing_timing, $s) ||
     209                    strpos($item->billing_frequency, $s) ||
     210                    strpos($item->free_trial_days, $s);
    187211            });
    188212        }
     
    200224
    201225        $fnames = [
    202             'code'          => function($item){ return $item->code;          },
    203             'name'          => function($item){ return $item->name;          },
    204             'provider_name' => function($item){ return $item->provider_name; },
    205             'price'         => function($item){ return $item->price;         },
    206             'currency'      => function($item){ return $item->currency;      },
    207             'button_name'   => function($item){ return $item->button_name;   }
     226            'code'          => function($item){ return $item->code;              },
     227            'name'          => function($item){ return $item->name;              },
     228            'provider_name' => function($item){ return $item->provider_name;    },
     229            'price'         => function($item){ return $item->price;             },
     230            'currency'      => function($item){ return $item->currency;          },
     231            'button_name'   => function($item){ return $item->button_name;       },
     232            'billing'       => function($item){
     233              $s = $item->billing_timing;
     234             
     235              return $s;
     236            },
     237            'billing_frequency' => function($item){ return $item->billing_frequency; },
     238            'free_trial_days'   => function($item){ return $item->free_trial_days;   }
    208239        ];
    209240
     
    269300            'price' => '価格',
    270301            'currency' => '通貨',
    271             'button_name' => 'ボタン名'
     302            'button_name' => 'ボタン名',
     303            'subscription' => '継続'
    272304        ];
    273305    }
     
    289321            case 'currency':      return esc_html($item->currency);
    290322            case 'button_name':   return esc_html($item->button_name);
     323            case 'subscription':  return esc_html($item->subscription);
    291324        }
    292325    }
     
    319352    }
    320353
     354    protected function column_subscription($item) {
     355        $billing_timing = esc_html($item->billing_timing);
     356        $subscription = '一括';
     357        if ($billing_timing === 'subscription') {
     358            $subscription = '定期';
     359            $billing_frequency = esc_html($item->billing_frequency);
     360            if ($billing_frequency === 'monthly') {
     361                $subscription .= '(月次)';
     362            } else if ($billing_frequency === 'yearly') {
     363                $subscription .= '(年次)';
     364            }
     365        }
     366        return "{$subscription}";
     367    }
     368
    321369    protected function handle_row_actions( $item, $column_name, $primary ) {
    322370        if( $column_name === $primary ) {
    323371            $actions = [
    324372                'edit'   => '<a href="?page=' . SimpleStripeCheckout::SLUG__PRODUCT_EDIT_FORM . '&' . SimpleStripeCheckout::PARAMETER__PRODUCT_CODE . '=' . $item->code . '">編集</a>',
    325                 'delete' => '<a href="?page=' . SimpleStripeCheckout::SLUG__PRODUCT_LIST                                    . '&action=delete&checked[]=' . $item->code . '">削除</a>'
     373                'delete' => '<a href="?page=' . SimpleStripeCheckout::SLUG__PRODUCT_LIST                                    . '&action=delete&checked[]=' . $item->code . '" onclick="return confirm(\'「' . $item->name . '」を削除しますか?\')">削除</a>'
    326374            ];
    327375            // div class = raw-actions がキモ
     
    341389            'price'         => 'price',
    342390            'currency'      => 'currency',
    343             'button_name'   => 'button_name'
     391            'button_name'   => 'button_name',
     392            'subscription'  => 'subscription'
    344393        ];
    345394    }
     
    351400     * このプラグインのバージョン
    352401     */
    353     const VERSION = '1.0.0';
     402    const VERSION = '1.1.0';
    354403
    355404    /**
     
    359408
    360409    /**
     410     * ショートコード(商品名)
     411     */
     412    const GSSC_PRODUCT_NAME = self::PLUGIN_ID . '-product-name';
     413
     414    /**
    361415     * このプラグインのスクリプトのハンドル名
    362416     */
     
    384438
    385439    /**
     440     * CredentialAction:Webhook設定
     441     */
     442    const CREDENTIAL_ACTION__HOOK_CONFIG = self::CREDENTIAL_ACTION . 'hook-config';
     443
     444    /**
    386445     * CredentialName(プレフィックス)
    387446     */
     
    402461     */
    403462    const CREDENTIAL_NAME__MAIL_CONFIG = self::CREDENTIAL_NAME . 'mail-config';
     463
     464    /**
     465     * CredentialName:Webhook設定
     466     */
     467    const CREDENTIAL_NAME__HOOK_CONFIG = self::CREDENTIAL_NAME . 'hook-config';
    404468
    405469    /**
     
    427491
    428492    /**
     493     * OPTIONSキー:定期支払キャンセル完了ページのSLUG
     494     * ※OPTIONSテーブルにセットする際のキー
     495     */
     496    const OPTION_KEY__CANCELED_SUBSCRIPTION_PAGE_SLUG = self::PLUGIN_PREFIX . 'canceled-subscription-page-slug';
     497
     498    /**
    429499     * OPTIONSキー:[初期設定] STRIPEの公開キー
    430500     * ※OPTIONSテーブルにセットする際のキー
     
    488558
    489559    /**
     560     * 画面のslug:Webhook設定
     561     */
     562    const SLUG__HOOK_CONFIG_FORM = self::PLUGIN_PREFIX . 'hook-config-form';
     563
     564    /**
    490565     * 画面のslug:STRIPE与信枠の確保
    491566     */
     
    498573
    499574    /**
     575     * 画面のslug:STRIPEサブスクリプションのキャンセル
     576     */
     577    const SLUG__CANCEL_SUBSCRIPTION = self::PLUGIN_PREFIX . 'cancel-subscription';
     578
     579    /**
     580     * 画面のslug:STRIPE定期支払キャンセル完了(パーマリンクにアンスコを使用できなかったのでハイフンを使用)
     581     */
     582    const SLUG__CANCELED_SUBSCRIPTION = self::PLUGIN_ID . '-' . 'canceled-subscription';
     583
     584    /**
     585     * 画面のslug:STRIPEサブスクリプションの毎月/毎年の支払完了
     586     */
     587    const SLUG__PAY_SUBSCRIPTION = self::PLUGIN_PREFIX . 'pay-subscription';
     588
     589    /**
    500590     * 画面のslug:STRIPE決済完了(パーマリンクにアンスコを使用できなかったのでハイフンを使用)
    501591     */
     
    556646     */
    557647    const PARAMETER__PRODUCT_BUTTON_NAME = self::PLUGIN_PREFIX . 'product-button-name';
     648
     649    /**
     650     * パラメータ名:[商品情報編集] 商品請求タイミング
     651     */
     652    const PARAMETER__PRODUCT_BILLING_TIMING = self::PLUGIN_PREFIX . 'product-billing-timing';
     653
     654    /**
     655     * パラメータ名:[商品情報編集] 商品請求間隔
     656     */
     657    const PARAMETER__PRODUCT_BILLING_FREQUENCY = self::PLUGIN_PREFIX . 'product-billing-frequency';
     658
     659    /**
     660     * パラメータ名:[商品情報編集] 商品無料トライアル
     661     */
     662    const PARAMETER__PRODUCT_FREE_TRIAL_DAYS = self::PLUGIN_PREFIX . 'product-free-trial-days';
    558663
    559664    /**
     
    619724
    620725    /**
     726     * TRANSIENTキー(一時入力値):[商品情報編集] 商品請求タイミング
     727     */
     728    const TRANSIENT_KEY__TEMP_PRODUCT_BILLING_TIMING = self::PLUGIN_PREFIX . 'temp-product-billing-timing';
     729
     730    /**
     731     * TRANSIENTキー(一時入力値):[商品情報編集] 商品請求間隔
     732     */
     733    const TRANSIENT_KEY__TEMP_PRODUCT_BILLING_FREQUENCY = self::PLUGIN_PREFIX . 'temp-product-billing-frequency';
     734
     735    /**
     736     * TRANSIENTキー(一時入力値):[商品情報編集] 商品無料トライアル
     737     */
     738    const TRANSIENT_KEY__TEMP_PRODUCT_FREE_TRIAL_DAYS = self::PLUGIN_PREFIX . 'temp-product-free-trial-days';
     739
     740    /**
    621741     * TRANSIENTキー(一時入力値):[メール設定] 販売者向け受信メルアド
    622742     */
     
    674794
    675795    /**
     796     * TRANSIENTキー(不正メッセージ):[商品情報編集] 商品請求タイミング
     797     */
     798    const TRANSIENT_KEY__INVALID_PRODUCT_BILLING_TIMING = self::PLUGIN_PREFIX . 'invalid-product-billing-timing';
     799
     800    /**
     801     * TRANSIENTキー(不正メッセージ):[商品情報編集] 商品請求間隔
     802     */
     803    const TRANSIENT_KEY__INVALID_PRODUCT_BILLING_FREQUENCY = self::PLUGIN_PREFIX . 'invalid-product-billing-frequency';
     804
     805    /**
     806     * TRANSIENTキー(不正メッセージ):[商品情報編集] 商品無料トライアル日数
     807     */
     808    const TRANSIENT_KEY__INVALID_PRODUCT_FREE_TRIAL_DAYS = self::PLUGIN_PREFIX . 'invalid-product-free-trial-days';
     809
     810    /**
    676811     * TRANSIENTキー(不正メッセージ):[メール設定] 販売者向け受信メルアド
    677812     */
     
    694829
    695830    /**
     831     * TRANSIENTキー(エラーメッセージ):[STRIPE] 商品登録失敗
     832     */
     833    const TRANSIENT_KEY__ERROR_STRIPE_PRODUCT_REGISTER = self::PLUGIN_PREFIX . 'error-stripe-product-register';
     834
     835    /**
     836     * TRANSIENTキー(エラーメッセージ):[STRIPE] 価格登録失敗
     837     */
     838    const TRANSIENT_KEY__ERROR_STRIPE_PRICE_REGISTER = self::PLUGIN_PREFIX . 'error-stripe-price-register';
     839
     840    /**
     841     * TRANSIENTキー(エラーメッセージ):[STRIPE] Webhook取得失敗
     842     */
     843    const TRANSIENT_KEY__ERROR_STRIPE_WEBHOOK_RETRIEVE = self::PLUGIN_PREFIX . 'error-stripe-webhook-retrieve';
     844
     845    /**
    696846     * TRANSIENTキー(保存完了メッセージ):初期設定
    697847     */
     
    709859
    710860    /**
     861     * TRANSIENTキー(保存完了メッセージ):Webhook設定
     862     */
     863    const TRANSIENT_KEY__SAVE_HOOK_CONFIG = self::PLUGIN_PREFIX . 'save-hook-config';
     864
     865    /**
    711866     * TRANSIENTのタイムリミット:5秒
    712867     */
     
    754909
    755910    /**
     911     * プロパティ名: ラベル
     912     */
     913    const LABEL = 'label';
     914
     915    /**
    756916     * STRIPE対応通貨リスト
    757917     */
    758918    const STRIPE_CURRENCIES = array(
    759         'USD'=>array('label'=>'USD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
    760         'AUD'=>array('label'=>'AUD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
    761         'BRL'=>array('label'=>'BRL (R$0.50以上)',   'min'=>0.50, 'format'=>'R$___'),
    762         'CAD'=>array('label'=>'CAD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
    763         'CHF'=>array('label'=>'CHF (0.50 Fr以上)',  'min'=>0.50, 'format'=>'___ Fr'),
    764         'DKK'=>array('label'=>'DKK (2.50-kr.以上)', 'min'=>2.50, 'format'=>'___-kr'),
    765         'EUR'=>array('label'=>'EUR (€0.50以上)',    'min'=>0.50, 'format'=>'€___'),
    766         'GBP'=>array('label'=>'GBP (£0.30以上)',    'min'=>0.30, 'format'=>'£___'),
    767         'HKD'=>array('label'=>'HKD ($4.00以上)',    'min'=>4.00, 'format'=>'$___'),
    768         'INR'=>array('label'=>'INR (₹0.50以上)',    'min'=>0.50, 'format'=>'₹___'),
    769         'JPY'=>array('label'=>'JPY (¥50以上)',     'min'=>50.0, 'format'=>'¥___'),
    770         'MXN'=>array('label'=>'MXN ($10以上)',      'min'=>10.0, 'format'=>'$___'),
    771         'MYR'=>array('label'=>'MYR (RM 2以上)',     'min'=>2.00, 'format'=>'RM ___'),
    772         'NOK'=>array('label'=>'NOK (3.00-kr.以上)', 'min'=>3.00, 'format'=>'___-kr.'),
    773         'NZD'=>array('label'=>'NZD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
    774         'PLN'=>array('label'=>'PLN (2.00 zł以上)',  'min'=>2.00, 'format'=>'___ zł'),
    775         'SEK'=>array('label'=>'SEK (3.00-kr.以上)', 'min'=>3.00, 'format'=>'___-kr.'),
    776         'SGD'=>array('label'=>'SGD ($0.50以上)',    'min'=>0.50, 'format'=>'$___')
     919        'USD'=>array(self::LABEL=>'USD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
     920        'AUD'=>array(self::LABEL=>'AUD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
     921        'BRL'=>array(self::LABEL=>'BRL (R$0.50以上)',   'min'=>0.50, 'format'=>'R$___'),
     922        'CAD'=>array(self::LABEL=>'CAD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
     923        'CHF'=>array(self::LABEL=>'CHF (0.50 Fr以上)',  'min'=>0.50, 'format'=>'___ Fr'),
     924        'DKK'=>array(self::LABEL=>'DKK (2.50-kr.以上)', 'min'=>2.50, 'format'=>'___-kr'),
     925        'EUR'=>array(self::LABEL=>'EUR (€0.50以上)',    'min'=>0.50, 'format'=>'€___'),
     926        'GBP'=>array(self::LABEL=>'GBP (£0.30以上)',    'min'=>0.30, 'format'=>'£___'),
     927        'HKD'=>array(self::LABEL=>'HKD ($4.00以上)',    'min'=>4.00, 'format'=>'$___'),
     928        'INR'=>array(self::LABEL=>'INR (₹0.50以上)',    'min'=>0.50, 'format'=>'₹___'),
     929        'JPY'=>array(self::LABEL=>'JPY (¥50以上)',     'min'=>50.0, 'format'=>'¥___'),
     930        'MXN'=>array(self::LABEL=>'MXN ($10以上)',      'min'=>10.0, 'format'=>'$___'),
     931        'MYR'=>array(self::LABEL=>'MYR (RM 2以上)',     'min'=>2.00, 'format'=>'RM ___'),
     932        'NOK'=>array(self::LABEL=>'NOK (3.00-kr.以上)', 'min'=>3.00, 'format'=>'___-kr.'),
     933        'NZD'=>array(self::LABEL=>'NZD ($0.50以上)',    'min'=>0.50, 'format'=>'$___'),
     934        'PLN'=>array(self::LABEL=>'PLN (2.00 zł以上)',  'min'=>2.00, 'format'=>'___ zł'),
     935        'SEK'=>array(self::LABEL=>'SEK (3.00-kr.以上)', 'min'=>3.00, 'format'=>'___-kr.'),
     936        'SGD'=>array(self::LABEL=>'SGD ($0.50以上)',    'min'=>0.50, 'format'=>'$___')
     937    );
     938
     939    /**
     940     * 商品請求タイミング: 一括
     941     */
     942    const STRIPE_BILLING_TIMING__LUMP_SUM = 'lump-sum-payment';
     943
     944    /**
     945     * 商品請求タイミング: 定期
     946     */
     947    const STRIPE_BILLING_TIMING__SUBSCRIPTION = 'subscription';
     948
     949    /**
     950     * 商品請求タイミング: リスト
     951     */
     952    const STRIPE_BILLING_TIMING_LIST = array(
     953        self::STRIPE_BILLING_TIMING__LUMP_SUM   => array(self::LABEL=>'一括'),
     954        self::STRIPE_BILLING_TIMING__SUBSCRIPTION => array(self::LABEL=>'定期')
     955    );
     956
     957    /**
     958     * 商品請求頻度リスト: 月次
     959     */
     960    const STRIPE_BILLING_FREQUENCY__MONTHLY = 'monthly';
     961
     962    /**
     963     * 商品請求頻度リスト: 年次
     964     */
     965    const STRIPE_BILLING_FREQUENCY__YEARLY = 'yearly';
     966
     967    /**
     968     * 商品請求頻度: リスト
     969     */
     970    const STRIPE_BILLING_FREQUENCY_LIST = array(
     971        'monthly'=>array(self::LABEL=>'月次'),
     972        'yearly'=>array(self::LABEL=>'年次')
    777973    );
    778974
     
    8861082
    8871083    /**
     1084     * HTMLのRADIOタグを生成・取得
     1085     */
     1086    static function makeHtmlRadios($list, $name, $selected, $label = null, $separate = '') {
     1087        $html = '';
     1088        foreach ($list as $key => $value) {
     1089            $html .= '<input type="radio" name="' . $name . '"value="' . $key . '"';
     1090            if ($key == $selected) {
     1091                $html .= ' checked';
     1092            }
     1093            $html .= '">' . (is_null($label) ? $value : $value[$label]) . '</option>';
     1094            $html .= $separate;
     1095        }
     1096        return $html;
     1097    }
     1098
     1099    /**
    8881100     * 購入者向け与信枠確保メール本文テンプレート
    8891101     */
    890     static function buyer_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $immediate_settlement) {
     1102    static function buyer_lump_sum_payment_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $immediate_settlement) {
    8911103        return "
    8921104${email}様
     
    9241136
    9251137    /**
     1138     * 購入者向けサブスクリプション登録完了メール本文テンプレート
     1139     */
     1140    static function buyer_subscription_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $billing_frequency, $trail_end_date) {
     1141        return "
     1142${email}様
     1143
     1144この度はありがとうございます。
     1145今後、以下の内容でお支払いが行われます。
     1146
     1147▼購入者様Eメール
     1148${email}
     1149
     1150▼内容
     1151${service_name}
     1152
     1153▼価格
     1154${amount}
     1155
     1156▼期間
     1157${billing_frequency}
     1158
     1159▼初回引落予定日
     1160${trail_end_date}
     1161
     1162▼お支払いに使われるカード下四桁
     1163${last4}
     1164
     1165▼定期払のキャンセル
     1166キャンセルする場合は以下をクリックするとキャンセル可能です。
     1167${cancel_url}
     1168
     1169------
     1170${site_name}
     1171${home_url}
     1172
     1173お支払いに関するお問い合わせ先
     1174${buyer_from_address}
     1175";
     1176    }
     1177
     1178    /**
    9261179     * 販売者向け与信枠確保メール本文テンプレート
    9271180     */
    928     static function seller_mail_template($email, $service_name, $amount, $last4, $capture_url, $site_name, $home_url, $immediate_settlement) {
     1181    static function seller_lump_sum_payment_mail_template($email, $service_name, $amount, $last4, $capture_url, $site_name, $home_url, $immediate_settlement) {
    9291182        return "
    9301183お申込み内容
     
    9561209
    9571210    /**
     1211     * 販売者向けサブスクリプション登録完了メール本文テンプレート
     1212     */
     1213    static function seller_subscription_mail_template($email, $service_name, $amount, $last4, $site_name, $home_url, $billing_frequency, $trail_end_date) {
     1214        return "
     1215お申込み内容
     1216
     1217▼購入者様Eメール
     1218${email}
     1219
     1220▼内容
     1221${service_name}
     1222
     1223▼価格
     1224${amount}
     1225
     1226▼期間
     1227${billing_frequency}
     1228
     1229▼初回引落予定日
     1230${trail_end_date}
     1231
     1232▼お支払いに使われたカード下四桁
     1233${last4}
     1234
     1235------
     1236${site_name}
     1237${home_url}
     1238
     1239";
     1240    }
     1241
     1242    /**
    9581243     * 購入者向けキャンセルメール本文テンプレート
    9591244     */
     
    10601345▼お支払いに使われたカード下四桁
    10611346${last4}
     1347
     1348------
     1349${site_name}
     1350${home_url}
     1351";
     1352    }
     1353
     1354    /**
     1355     * 購入者向けサブスクリプション支払完了メール本文テンプレート
     1356     */
     1357    static function buyer_pay_subscription_mail_template($email, $service_name, $amount, $last4, $next_date, $site_name, $home_url, $buyer_from_address) {
     1358        return "
     1359${email}様
     1360
     1361${service_name} の支払いが行われましたので、
     1362ご連絡のメールとなります。
     1363
     1364▼購入者様Eメール
     1365${email}
     1366
     1367▼内容
     1368${service_name}
     1369
     1370▼価格
     1371${amount}
     1372
     1373▼お支払いに使われたカード下四桁
     1374${last4}
     1375
     1376▼次回引落予定日
     1377${next_date}
     1378
     1379------
     1380${site_name}
     1381${home_url}
     1382
     1383お支払いに関するお問い合わせ先
     1384${buyer_from_address}
     1385";
     1386    }
     1387
     1388    /**
     1389     * 販売者向けサブスクリプション支払完了メール本文テンプレート
     1390     */
     1391    static function seller_pay_subscription_mail_template($email, $service_name, $amount, $last4, $next_date, $site_name, $home_url) {
     1392        return "
     1393お客様にて、お支払いの確定がありましたので、
     1394以下のお支払いが行われました。
     1395
     1396▼購入者様Eメール
     1397${email}
     1398
     1399▼内容
     1400${service_name}
     1401
     1402▼価格
     1403${amount}
     1404
     1405▼お支払いに使われたカード下四桁
     1406${last4}
     1407
     1408▼次回引落予定日
     1409${next_date}
    10621410
    10631411------
     
    10951443        // ショートコード処理を登録
    10961444        add_shortcode(self::PLUGIN_ID, [$this, 'short_code']);
     1445        add_shortcode(self::GSSC_PRODUCT_NAME, [$this, 'short_code_product_name']);
    10971446
    10981447        // STRIPEの与信枠の確保処理の準備:
     
    11021451        // STRIPEの決済の確定処理の準備:
    11031452        add_rewrite_endpoint(self::SLUG__CAPTURE, EP_ALL);
     1453        // STRIPEのサブスクリプションのキャンセル処理の準備
     1454        add_rewrite_endpoint(self::SLUG__CANCEL_SUBSCRIPTION, EP_ALL);
     1455        // STRIPEのサブスクリプションの毎月/毎年の支払完了受信処理の準備
     1456        add_rewrite_endpoint(self::SLUG__PAY_SUBSCRIPTION, EP_ALL);
    11041457
    11051458        // ページを表示する直前の前処理をフック(STRIPEのチェックアウト処理を追加)
     
    11231476            add_action('admin_init', [$this, 'save_product']);
    11241477            // 管理画面各ページの最初、ページがレンダリングされる前に実行するアクションに、
    1125             // 初期設定を保存する関数をフック
     1478            // メール設定を保存する関数をフック
    11261479            add_action('admin_init', [$this, 'save_mail_config']);
     1480            // 管理画面各ページの最初、ページがレンダリングされる前に実行するアクションに、
     1481            // Webhook設定を保存する関数をフック
     1482            add_action('admin_init', [$this, 'save_hook_config']);
    11271483           
    11281484        }
     
    11371493
    11381494    /**
    1139      * ショートコード処理
     1495     * ショートコード処理(購入ボタン)
    11401496     */
    11411497    function short_code($atts, $content = null) {
     
    11511507                // STRIPEの公開キーをOPTIONSテーブルから取得
    11521508                $stripe_public_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_PUBLIC_KEY), self::ENCRYPT_PASSWORD);
    1153                 // 商品情報リストをOPTIONSテーブルから取得
    1154                 $product_list = get_option(self::OPTION_KEY__PRODUCT_LIST);
    1155                 // 商品情報リストがある場合
    1156                 if (!is_null($product_list)) {
    1157                     // 商品情報リストをアンシリアライズ
    1158                     $product_list = unserialize($product_list);
    1159                     // アンシリアライズした商品情報リストが正しく配列の場合
    1160                     if (is_array($product_list)) {
    1161                         for ($i = 0; $i < count($product_list); $i++) {
    1162                             if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
    1163                                 // 商品コードが一致する場合
    1164                                 if ($product_list[$i]->code == $product_code) {
    1165                                     $product = $product_list[$i];
    1166                                 }
    1167                             }
    1168                         }
    1169                     }
    1170                 }
     1509                // OPTIONSテーブルから商品情報を取得
     1510                $product = $this->getProduct($product_code);
    11711511                // 商品情報がある場合
    11721512                if (isset($product)) {
     
    11811521                    // 商品ボタン名
    11821522                    $product_button_name = $product->button_name;
     1523                    // 商品定期支払種別
     1524                    $product_subscription = $product->subscription;
    11831525                    // 決済URL
    11841526                    $url = '?' . self::SLUG__CHECKOUT . "=" . $product->code;
     
    12141556
    12151557    /**
    1216      * ページを表示する直前の前処理をフック(STRIPEのチェックアウト処理を追加)
    1217      */
    1218     function on_template_redirect() {
    1219         // STRIPEの与信枠の確保をするために対象の商品コードをURLクエリーから取得
    1220         $checkout = get_query_var(self::SLUG__CHECKOUT);
    1221         // 商品コードを取得
    1222         $product_code = intval($checkout);
    1223         // 商品コードがある場合
    1224         if ($product_code > 0) {
    1225             // STRIPEの与信枠の確保処理
    1226             $this->checkout($product_code);
    1227         }
    1228         // STRIPEの与信枠の確保キャンセル処理をするために対象の料金IDをURLクエリーから取得
    1229         // ex) ch_zd4gENPfuT06SdQwWrsn
    1230         $refund = get_query_var(self::SLUG__REFUND);
    1231         // 与信枠の確保キャンセルの場合
    1232         // ex) ch_zd4gENPfuT06SdQwWrsn
    1233         if (strlen($refund) > 0) {
    1234             // STRIPEの与信枠の確保キャンセル処理
    1235             $this->refund($refund);
    1236         }
    1237         // STRIPEの決済の確定処理をするために対象の料金IDをURLクエリーから取得
    1238         // ex) ch_zd4gENPfuT06SdQwWrsn
    1239         $capture = get_query_var(self::SLUG__CAPTURE);
    1240         // 決済確定の場合
    1241         if (strlen($capture) > 0) {
    1242             // STRIPEの決済を確定処理
    1243             $this->capture($capture);
    1244         }
    1245        
    1246     }
    1247 
    1248     /**
    1249      * STRIPEの与信枠の確保処理
    1250      */
    1251     function checkout($product_code) {
    1252         // STRIPEのライブラリを読み込む
    1253         require_once( dirname(__FILE__).'/lib/stripe-php-7.7.1/init.php');
    1254         // STRIPEのシークレットキーをOPTIONSテーブルから取得
    1255         $stripe_secret_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_SECRET_KEY), self::ENCRYPT_PASSWORD);
    1256         // STRIPEのシークレットキーをセット
    1257         \Stripe\Stripe::setApiKey($stripe_secret_key);
    1258         // STRIPEのトークンと決済者のメルアドを取得
    1259         $token = trim(sanitize_text_field($_POST['stripeToken']));
    1260         $email = trim(sanitize_text_field($_POST['stripeEmail']));
     1558     * ショートコード処理(商品名)
     1559     */
     1560    function short_code_product_name($atts, $content = null) {
     1561        $val = '';
     1562        // 商品コード
     1563        $product_code = intval(trim(sanitize_text_field($_GET['product_id'])));
     1564        // STRIPEの公開キーをOPTIONSテーブルから取得
     1565        $stripe_public_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_PUBLIC_KEY), self::ENCRYPT_PASSWORD);
     1566        // OPTIONSテーブルから商品情報を取得
     1567        $product = $this->getProduct($product_code);
     1568        // 商品情報がある場合
     1569        if (isset($product)) {
     1570            // 商品価格
     1571            $product_price = $product->price;
     1572            // 商品通貨
     1573            $product_currency = strtolower($product->currency);
     1574            // 商品提供者名
     1575            $product_provider_name = $product->provider_name;
     1576            // 商品名
     1577            $product_name = $product->name;
     1578            // 商品ボタン名
     1579            $product_button_name = $product->button_name;
     1580            // STRIPEの購入ボタンのHTMLを作成
     1581            $val = 'キャンセルされたお支払い:' . $product_name;
     1582        }
     1583        return $val;
     1584    }
     1585
     1586    /**
     1587     * OPTION情報から任意の商品情報を取得
     1588     */
     1589    function getProduct($product_code) {
    12611590        // 商品情報リストをOPTIONSテーブルから取得
    12621591        $product_list = get_option(self::OPTION_KEY__PRODUCT_LIST);
     
    12711600                        // 商品コードが一致する場合
    12721601                        if ($product_list[$i]->code == $product_code) {
    1273                             $product = $product_list[$i];
     1602                            return $product_list[$i];
    12741603                        }
    12751604                    }
     
    12771606            }
    12781607        }
     1608        return null;
     1609    }
     1610
     1611    /**
     1612     * ページを表示する直前の前処理をフック(STRIPEのチェックアウト処理を追加)
     1613     */
     1614    function on_template_redirect() {
     1615        // STRIPEの与信枠の確保をするために対象の商品コードをURLクエリーから取得
     1616        $checkout = get_query_var(self::SLUG__CHECKOUT);
     1617        // 商品コードを取得
     1618        $product_code = intval($checkout);
     1619        // 商品コードがある場合
     1620        if ($product_code > 0) {
     1621            // STRIPEの一括払いと定期払いの共通前処理
     1622            list($billing_timing, $token, $email, $product, $immediate_settlement) = $this->precheck($product_code);
     1623            // 一括払いの場合
     1624            if ($billing_timing === self::STRIPE_BILLING_TIMING__LUMP_SUM) {
     1625                // STRIPEの与信枠の確保処理
     1626                $this->checkout($token, $email, $product, $immediate_settlement);
     1627            }
     1628            // 分割払いの場合
     1629            else if ($billing_timing === self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     1630                // STRIPEのサブスクリプション処理
     1631                $this->subscribe($token, $email, $product, $immediate_settlement);
     1632            }
     1633        }
     1634        // STRIPEの与信枠の確保キャンセル処理をするために対象の料金IDをURLクエリーから取得
     1635        // ex) ch_zd400000000000000rsn
     1636        $refund = get_query_var(self::SLUG__REFUND);
     1637        // 与信枠の確保キャンセルの場合
     1638        // ex) ch_zd4gENPfuT06SdQwWrsn
     1639        if (strlen($refund) > 0) {
     1640            // STRIPEの与信枠の確保キャンセル処理
     1641            $this->refund($refund);
     1642        }
     1643        // STRIPEの決済の確定処理をするために対象の料金IDをURLクエリーから取得
     1644        // ex) ch_zd400000000000000rsn
     1645        $capture = get_query_var(self::SLUG__CAPTURE);
     1646        // 決済確定の場合
     1647        if (strlen($capture) > 0) {
     1648            // STRIPEの決済を確定処理
     1649            $this->capture($capture);
     1650        }
     1651        // STRIPEのサブスクリプションのキャンセル処理をするために対象のサブスクリプションIDをURLクエリーから取得
     1652        // ex) sub_zd40000000000000rsn
     1653        $subscription = get_query_var(self::SLUG__CANCEL_SUBSCRIPTION);
     1654        if (strlen($subscription) > 0) {
     1655            // STRIPEのサブスクリプションのキャンセル処理
     1656            $this->cancelSubscription($subscription);
     1657        }
     1658        // STRIPEのサブスクリプションの毎月/毎年の支払完了受信処理をするために値をURLクエリーから取得
     1659        // ex) true
     1660        $pay_subscription = get_query_var(self::SLUG__PAY_SUBSCRIPTION);
     1661        if (strlen($pay_subscription) > 0) {
     1662            // STRIPEのサブスクリプションの毎月/毎年の支払完了受信処理
     1663            $this->paySubscription();
     1664        }
     1665    }
     1666
     1667    /**
     1668     * STRIPEのAPIを初期化
     1669     */
     1670    function initStripeApi() {
     1671        // STRIPEのライブラリを読み込む
     1672        require_once( dirname(__FILE__).'/lib/stripe-php-7.7.1/init.php');
     1673        // STRIPEのシークレットキーをOPTIONSテーブルから取得
     1674        $stripe_secret_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_SECRET_KEY), self::ENCRYPT_PASSWORD);
     1675        // STRIPEのシークレットキーをセット
     1676        \Stripe\Stripe::setApiKey($stripe_secret_key);
     1677    }
     1678
     1679    /**
     1680     * STRIPEの一括払いと定期払いの共通前処理
     1681     */
     1682    function precheck($product_code) {
     1683        // STRIPEのAPIを初期化
     1684        $this->initStripeApi();
     1685        // STRIPEのトークンと決済者のメルアドを取得
     1686        $token = trim(sanitize_text_field($_POST['stripeToken']));
     1687        $email = trim(sanitize_text_field($_POST['stripeEmail']));
     1688        // OPTIONSテーブルから商品情報を取得
     1689        $product = $this->getProduct($product_code);
    12791690        // 商品情報がない場合
    12801691        if (!isset($product)) {
     
    12901701        }
    12911702        $immediate_settlement = ($immediate_settlement === 'ON');
     1703        return array($product->billing_timing, $token, $email, $product, $immediate_settlement);
     1704    }
     1705
     1706    /**
     1707     * STRIPEの与信枠の確保処理
     1708     */
     1709    function checkout($token, $email, $product, $immediate_settlement) {
    12921710        // 決済結果
    12931711        $charge = null;
     
    13561774        // サイトURL
    13571775        $home_url = home_url();
     1776        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     1777        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
    13581778        // 購入者向けメール送信
    13591779        if (self::send_mail(
     
    13611781            "${service_name}へのお支払いありがとうございます。",
    13621782            // 本文
    1363             self::buyer_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $immediate_settlement),
     1783            self::buyer_lump_sum_payment_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $immediate_settlement),
    13641784            // 宛先
    13651785            $email,
    13661786            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
    1367             get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS)
     1787            $buyer_from_address
    13681788        )) {
    13691789            echo "メールを送信しました";
     
    13761796            "${service_name}へのお支払いがありました。",
    13771797            // 本文
    1378             self::seller_mail_template($email, $service_name, $amount, $last4, $capture_url, $site_name, $home_url, $immediate_settlement),
     1798            self::seller_lump_sum_payment_mail_template($email, $service_name, $amount, $last4, $capture_url, $site_name, $home_url, $immediate_settlement),
    13791799            // 宛先(販売者向け受信メルアドをOPTIONSテーブルから取得)
    13801800            get_option(self::OPTION_KEY__SELLER_RECEIVE_ADDRESS),
     
    13961816
    13971817    /**
     1818     * STRIPEのサブスクリプション処理
     1819     */
     1820    function subscribe($token, $email, $product, $immediate_settlement) {
     1821        // 決済結果
     1822        $charge = null;
     1823        // 料金ID
     1824        $charge_id = null;
     1825        // フォームから情報を取得:
     1826        try {
     1827            $customer = \Stripe\Customer::create(array(
     1828                'email' => $email,
     1829                'source'  => $token,
     1830            ));
     1831            $subscription = \Stripe\Subscription::create(array(
     1832                'customer' => $customer->id,
     1833              'trial_from_plan' => true,
     1834                'items' => array(
     1835                  array('price' => $product->stripe_plan_id)
     1836              ),
     1837            ));
     1838        } catch (\Stripe\Exception\ApiErrorException $e) {
     1839            $error = $e->getError();
     1840            if (isset($customer) && $customer->id !== null) {
     1841              // Customerを削除すればSubscriptionも削除される
     1842              \Stripe\Customer::delete(array(
     1843                'id' => $customer->id
     1844              ));
     1845            }
     1846            die('サブスクリプションの登録に失敗しました [' . $error->type . ':' . $error->message . ']');
     1847        }
     1848        /*
     1849        if (isset($customer) && $customer->id !== null) {
     1850            $customer->delete();
     1851        }
     1852        die();
     1853        */
     1854        // カード番号下4桁
     1855        $last4 = "----";
     1856        // 金額
     1857        $amount = 0;
     1858        // サービス名
     1859        $service_name = '----';
     1860        // メルアド
     1861        $email = '----';
     1862        // サブスクリプション登録が完了した場合
     1863        if ($subscription) {
     1864            // 金額を取得
     1865            if (isset($subscription->plan) && isset($subscription->plan->amount)) {
     1866                $amount = $subscription->plan->amount;
     1867            }
     1868            // サービス名を取得
     1869            if (isset($product->name)) {
     1870                $service_name = $product->name;
     1871            }
     1872            if (isset($customer->sources)) {
     1873                // カード番号下4桁を取得
     1874                if (isset($customer->sources->data[0]->last4)) {
     1875                    $last4 = $customer->sources->data[0]->last4;
     1876                }
     1877                // メルアドを取得
     1878                if (isset($customer->sources->data[0]->name)) {
     1879                    $email = $customer->sources->data[0]->name;
     1880                }
     1881            }
     1882        }
     1883        $amount = str_replace('___', $amount, self::STRIPE_CURRENCIES[strtoupper($product->currency)]['format']);
     1884        // キャンセルURL
     1885        $cancel_url = home_url() . '/?' . self::SLUG__CANCEL_SUBSCRIPTION . '=' . $subscription->id;
     1886        // サイト名
     1887        $site_name = get_bloginfo('name');
     1888        // サイトURL
     1889        $home_url = home_url();
     1890        // 請求間隔(月次 or 年次)
     1891        $billing_frequency = '';
     1892        if (isset(self::STRIPE_BILLING_FREQUENCY_LIST[$product->billing_frequency])) {
     1893            $billing_frequency = self::STRIPE_BILLING_FREQUENCY_LIST[$product->billing_frequency][self::LABEL];
     1894        }
     1895        // 初回引落予定日
     1896        $trail_end_date = date('Y年m月d日', $subscription->trial_end);
     1897        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     1898        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
     1899        // 購入者向けメール送信
     1900        if (self::send_mail(
     1901            // タイトル
     1902            "${service_name}への定期払登録ありがとうございます。",
     1903            // 本文
     1904            self::buyer_subscription_mail_template($email, $service_name, $amount, $last4, $cancel_url, $site_name, $home_url, $buyer_from_address, $billing_frequency, $trail_end_date),
     1905            // 宛先
     1906            $email,
     1907            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     1908            $buyer_from_address
     1909        )) {
     1910            echo "メールを送信しました";
     1911        } else {
     1912            echo "メールの送信に失敗しました";
     1913        }
     1914        // 販売者向けメール送信
     1915        if (self::send_mail(
     1916            // タイトル
     1917            "${service_name}への定期払登録がありました。",
     1918            // 本文
     1919            self::seller_subscription_mail_template($email, $service_name, $amount, $last4, $site_name, $home_url, $billing_frequency, $trail_end_date),
     1920            // 宛先(販売者向け受信メルアドをOPTIONSテーブルから取得)
     1921            get_option(self::OPTION_KEY__SELLER_RECEIVE_ADDRESS),
     1922            // 送信元(販売者向け送信元メルアドをOPTIONSテーブルから取得)
     1923            get_option(self::OPTION_KEY__SELLER_FROM_ADDRESS)
     1924        )) {
     1925            echo "メールを送信しました";
     1926        } else {
     1927            echo "メールの送信に失敗しました";
     1928        };
     1929        // サンキューページへリダイレクト
     1930        $checkedout_page_slug = get_option(SimpleStripeCheckout::OPTION_KEY__CHECKEDOUT_PAGE_SLUG);
     1931        if (strlen($checkedout_page_slug) === 0) {
     1932            $checkedout_page_slug = SimpleStripeCheckout::SLUG__CHECKEDOUT;
     1933        }
     1934        wp_safe_redirect(home_url('/' . $checkedout_page_slug), 303);
     1935        exit;
     1936    }
     1937
     1938    /**
    13981939     * STRIPEの与信枠の確保キャンセル処理
    13991940     */
    14001941    function refund($charge_id) {
    1401         // STRIPEのライブラリを読み込む
    1402         require_once( dirname(__FILE__).'/lib/stripe-php-7.7.1/init.php');
    1403         // STRIPEのシークレットキーをOPTIONSテーブルから取得
    1404         $stripe_secret_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_SECRET_KEY), self::ENCRYPT_PASSWORD);
    1405         // STRIPEのシークレットキーをセット
    1406         \Stripe\Stripe::setApiKey($stripe_secret_key);
     1942        // STRIPEのAPIを初期化
     1943        $this->initStripeApi();
    14071944        // 決済結果
    14081945        $charge = null;
     
    14722009        // サイトURL
    14732010        $home_url = home_url();
     2011        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2012        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
    14742013        // 購入者向けメール送信
    14752014        if (self::send_mail(
     
    14812020            $email,
    14822021            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
    1483             get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS)
     2022            $buyer_from_address
    14842023        )) {
    14852024            echo "メールを送信しました";
     
    15152054     */
    15162055    function capture($charge_id) {
    1517         // STRIPEのライブラリを読み込む
    1518         require_once( dirname(__FILE__).'/lib/stripe-php-7.7.1/init.php');
    1519         // STRIPEのシークレットキーをOPTIONSテーブルから取得
    1520         $stripe_secret_key = self::decrypt(get_option(self::OPTION_KEY__STRIPE_SECRET_KEY), self::ENCRYPT_PASSWORD);
    1521         // STRIPEのシークレットキーをセット
    1522         \Stripe\Stripe::setApiKey($stripe_secret_key);
     2056        // STRIPEのAPIを初期化
     2057        $this->initStripeApi();
    15232058        // 決済結果
    15242059        $charge = null;
     
    15842119        // サイトURL
    15852120        $home_url = home_url();
     2121        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2122        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
    15862123        // 購入者向けメール送信
    15872124        if (self::send_mail(
     
    15932130            $email,
    15942131            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
    1595             get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS)
     2132            $buyer_from_address
    15962133        )) {
    15972134            echo "メールを送信しました";
     
    16202157        }
    16212158        wp_safe_redirect(home_url('/' . $capture_complete_page_slug), 303);
     2159        exit;
     2160    }
     2161
     2162    /**
     2163     * STRIPEのサブスクリプションのキャンセル処理
     2164     */
     2165    function cancelSubscription($subscription_id) {
     2166        // STRIPEのAPIを初期化
     2167        $this->initStripeApi();
     2168        $cancel = false;
     2169        try {
     2170            $subscription = \Stripe\Subscription::retrieve($subscription_id);
     2171            // サブスクリプションが存在しない場合
     2172            if (!isset($subscription)) {
     2173                die('サブスクリプションが存在しません。');
     2174            }
     2175            // キャンセル済の場合
     2176            if ($subscription['status'] === 'canceled') {
     2177                die('サブスクリプションは既にキャンセルされています。');
     2178            }
     2179            // 商品情報取得
     2180            $product = \Stripe\Product::retrieve($subscription->plan->product);
     2181            // 商品情報が存在しない場合
     2182            if (!isset($product)) {
     2183                die('商品情報が存在しません。[code: stripe]');
     2184            }
     2185            // OPTIONSテーブルから商品情報を取得
     2186            $product_list = get_option(self::OPTION_KEY__PRODUCT_LIST);
     2187            if (!is_null($product_list)) {
     2188                $product_list = unserialize($product_list);
     2189                if (is_array($product_list)) {
     2190                    for ($i = 0; $i < count($product_list); $i++) {
     2191                        if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
     2192                            // 商品コードが一致する場合
     2193                            if ($product_list[$i]->stripe_plan_id == $subscription->plan->id) {
     2194                                $optionsProduct = $product_list[$i];
     2195                            }
     2196                        }
     2197                    }
     2198                }
     2199            }
     2200            if (!isset($optionsProduct)) {
     2201                die('商品情報が存在しません。[code: options]');
     2202            }
     2203            // 顧客情報取得
     2204            $customer = \Stripe\Customer::retrieve($subscription->customer);
     2205            //顧客情報が存在しない場合
     2206            if (!isset($customer)) {
     2207                die('顧客情報が存在しません。');
     2208            }
     2209            $subscription->cancel();
     2210        } catch (\Stripe\Exception\ApiErrorException $e) {
     2211            $error = $e->getError();
     2212            die('サブスクリプションのキャンセルに失敗しました [' . $error->type . ':' . $error->message . ']');
     2213        }
     2214        echo 'サブスクリプションをキャンセルしました。';
     2215        // サービス名
     2216        $service_name = '----';
     2217        if (isset($product->name)) {
     2218            $service_name = $product->name;
     2219        }
     2220        // カード番号下4桁
     2221        $last4 = "----";
     2222        if (isset($customer->sources)) {
     2223            if (isset($customer->sources->data)) {
     2224                if (count($customer->sources->data) > 0) {
     2225                    if (isset($customer->sources->data[0]->last4)) {
     2226                        $last4 = $customer->sources->data[0]->last4;
     2227                    }
     2228                }
     2229            }
     2230        }
     2231        // 金額
     2232        $amount = 0;
     2233        if (isset($subscription->plan)) {
     2234            if (isset($subscription->plan->amount)) {
     2235                $amount = $subscription->plan->amount;
     2236            }
     2237        }
     2238        // 通貨
     2239        $currency = '----';
     2240        if (isset($subscription->plan)) {
     2241            if (isset($subscription->plan->currency)) {
     2242                $currency = $subscription->plan->currency;
     2243            }
     2244        }
     2245       
     2246        // メルアド
     2247        $email = '----';
     2248        if (isset($customer->email)) {
     2249            $email = $customer->email;
     2250        }
     2251        // 価格に単位を付ける
     2252        $amount = str_replace('___', $amount, self::STRIPE_CURRENCIES[strtoupper($currency)]['format']);
     2253        // サイト名
     2254        $site_name = get_bloginfo('name');
     2255        // サイトURL
     2256        $home_url = home_url();
     2257        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2258        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
     2259        // 購入者向けメール送信
     2260        if (self::send_mail(
     2261            // タイトル
     2262            "${service_name}がキャンセルされました。",
     2263            // 本文
     2264            self::buyer_cancel_mail_template($email, $service_name, $amount, $last4, $site_name, $home_url, $buyer_from_address),
     2265            // 宛先
     2266            $email,
     2267            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2268            $buyer_from_address
     2269        )) {
     2270            echo "メールを送信しました";
     2271        } else {
     2272            echo "メールの送信に失敗しました";
     2273        }
     2274        // 販売者向けメール送信
     2275        if (self::send_mail(
     2276            // タイトル
     2277            "${service_name}がキャンセルされました。",
     2278            // 本文
     2279            self::seller_cancel_mail_template($email, $service_name, $amount, $last4, $site_name, $home_url),
     2280            // 宛先(販売者向け受信メルアドをOPTIONSテーブルから取得)
     2281            get_option(self::OPTION_KEY__SELLER_RECEIVE_ADDRESS),
     2282            // 送信元(販売者向け送信元メルアドをOPTIONSテーブルから取得)
     2283            get_option(self::OPTION_KEY__SELLER_FROM_ADDRESS)
     2284        )) {
     2285            echo "メールを送信しました";
     2286        } else {
     2287            echo "メールの送信に失敗しました";
     2288        };
     2289        // キャンセル完了ページへリダイレクト
     2290        $cancel_page_slug = get_option(SimpleStripeCheckout::OPTION_KEY__CANCELED_SUBSCRIPTION_PAGE_SLUG );
     2291        if (strlen($cancel_page_slug) === 0) {
     2292            $cancel_page_slug = SimpleStripeCheckout::SLUG__CANCELED_SUBSCRIPTION;
     2293        }
     2294        wp_safe_redirect(home_url('/' . $cancel_page_slug), 303);
     2295        exit;
     2296    }
     2297
     2298    /**
     2299     * STRIPEのサブスクリプションの支払完了イベント受信処理
     2300     */
     2301    function paySubscription() {
     2302        $json = json_decode(file_get_contents('php://input'), true);
     2303        // サブスクリプションID
     2304        $subscription_id = '';
     2305        if (isset($json)) {
     2306            if (isset($json['data'])) {
     2307                if (isset($json['data']['object'])) {
     2308                    if (isset($json['data']['object']['billing_reason'])) {
     2309                      if ($json['data']['object']['billing_reason'] !== 'subscription_cycle') {
     2310                        die('定期支払リサイクルではない。');
     2311                      }
     2312                    }
     2313                    if (isset($json['data']['object']['subscription'])) {
     2314                        $subscription_id = $json['data']['object']['subscription'];
     2315                    }
     2316                }
     2317            }
     2318        }
     2319        // STRIPEのAPIを初期化
     2320        $this->initStripeApi();
     2321        try {
     2322            $subscription = \Stripe\Subscription::retrieve($subscription_id);
     2323            // サブスクリプションが存在しない場合
     2324            if (!isset($subscription)) {
     2325                die('サブスクリプションが存在しません。');
     2326            }
     2327            // キャンセル済の場合
     2328            if ($subscription['status'] === 'canceled') {
     2329                die('サブスクリプションは既にキャンセルされています。');
     2330            }
     2331            // 商品情報取得
     2332            $product = \Stripe\Product::retrieve($subscription->plan->product);
     2333            // 商品情報が存在しない場合
     2334            if (!isset($product)) {
     2335                die('商品情報が存在しません。[code: stripe]');
     2336            }
     2337            // OPTIONSテーブルから商品情報を取得
     2338            $product_list = get_option(self::OPTION_KEY__PRODUCT_LIST);
     2339            if (!is_null($product_list)) {
     2340                $product_list = unserialize($product_list);
     2341                if (is_array($product_list)) {
     2342                    for ($i = 0; $i < count($product_list); $i++) {
     2343                        if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
     2344                            // 商品コードが一致する場合
     2345                            if ($product_list[$i]->stripe_plan_id == $subscription->plan->id) {
     2346                                $optionsProduct = $product_list[$i];
     2347                            }
     2348                        }
     2349                    }
     2350                }
     2351            }
     2352            if (!isset($optionsProduct)) {
     2353                die('商品情報が存在しません。[code: options]');
     2354            }
     2355            // 顧客情報取得
     2356            $customer = \Stripe\Customer::retrieve($subscription->customer);
     2357            //顧客情報が存在しない場合
     2358            if (!isset($customer)) {
     2359                die('顧客情報が存在しません。');
     2360            }
     2361        } catch (\Stripe\Exception\ApiErrorException $e) {
     2362            $error = $e->getError();
     2363            die('サブスクリプションの支払完了メール送信処理に失敗しました [' . $error->type . ':' . $error->message . ']');
     2364        }
     2365        // サービス名
     2366        $service_name = '----';
     2367        if (isset($product->name)) {
     2368            $service_name = $product->name;
     2369        }
     2370        // カード番号下4桁
     2371        $last4 = "----";
     2372        if (isset($customer->sources)) {
     2373            if (isset($customer->sources->data)) {
     2374                if (count($customer->sources->data) > 0) {
     2375                    if (isset($customer->sources->data[0]->last4)) {
     2376                        $last4 = $customer->sources->data[0]->last4;
     2377                    }
     2378                }
     2379            }
     2380        }
     2381        // 金額
     2382        $amount = 0;
     2383        if (isset($subscription->plan)) {
     2384            if (isset($subscription->plan->amount)) {
     2385                $amount = $subscription->plan->amount;
     2386            }
     2387        }
     2388        // 通貨
     2389        $currency = '----';
     2390        if (isset($subscription->plan)) {
     2391            if (isset($subscription->plan->currency)) {
     2392                $currency = $subscription->plan->currency;
     2393            }
     2394        }
     2395        // 次回支払予定日
     2396        $next_date = '----';
     2397        if (isset($json)) {
     2398            if (isset($json['data'])) {
     2399                if (isset($json['data']['object'])) {
     2400                    if (isset($json['data']['object']['lines'])) {
     2401                        if (isset($json['data']['object']['lines']['data'])) {
     2402                            if (isset($json['data']['object']['lines']['data'][0])) {
     2403                                if (isset($json['data']['object']['lines']['data'][0]['period'])) {
     2404                                    if (isset($json['data']['object']['lines']['data'][0]['period']['end'])) {
     2405                                        $next_date = date("Y年m月d日", $json['data']['object']['lines']['data'][0]['period']['end']);
     2406                                    }
     2407                                }
     2408                            }
     2409                        }
     2410                    }
     2411                }
     2412            }
     2413        }
     2414        // メルアド
     2415        $email = '----';
     2416        if (isset($customer->email)) {
     2417            $email = $customer->email;
     2418        }
     2419        // 価格に単位を付ける
     2420        $amount = str_replace('___', $amount, self::STRIPE_CURRENCIES[strtoupper($currency)]['format']);
     2421        // サイト名
     2422        $site_name = get_bloginfo('name');
     2423        // サイトURL
     2424        $home_url = home_url();
     2425        // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2426        $buyer_from_address = get_option(self::OPTION_KEY__BUYER_FROM_ADDRESS);
     2427        // 購入者向けメール送信
     2428        if (self::send_mail(
     2429            // タイトル
     2430            "${service_name} の支払いが行われました。",
     2431            // 本文
     2432            self::buyer_pay_subscription_mail_template($email, $service_name, $amount, $last4, $next_date, $site_name, $home_url, $buyer_from_address),
     2433            // 宛先
     2434            $email,
     2435            // 送信元(購入者向け送信元メルアドをOPTIONSテーブルから取得)
     2436            $buyer_from_address
     2437        )) {
     2438            echo "購入者宛メールを送信しました。";
     2439        } else {
     2440            echo "購入者宛メールの送信に失敗しました。";
     2441        }
     2442        // 販売者向けメール送信
     2443        if (self::send_mail(
     2444            // タイトル
     2445            "${service_name} の支払いが行われました。",
     2446            // 本文
     2447            self::seller_pay_subscription_mail_template($email, $service_name, $amount, $last4, $next_date, $site_name, $home_url),
     2448            // 宛先(販売者向け受信メルアドをOPTIONSテーブルから取得)
     2449            get_option(self::OPTION_KEY__SELLER_RECEIVE_ADDRESS),
     2450            // 送信元(販売者向け送信元メルアドをOPTIONSテーブルから取得)
     2451            get_option(self::OPTION_KEY__SELLER_FROM_ADDRESS)
     2452        )) {
     2453            echo "販売者宛メールを送信しました。";
     2454        } else {
     2455            echo "販売者宛メールの送信に失敗しました。";
     2456        };
    16222457        exit;
    16232458    }
     
    17832618            [$this, 'show_mail_config_form']
    17842619        );
     2620       
     2621        // サブメニュー「Webhook」を追加
     2622        add_submenu_page(
     2623            // 親メニューのslug:
     2624            self::SLUG__TOP,
     2625            //ページタイトル:
     2626            'Webhook',
     2627            //メニュータイトル:
     2628            'Webhook',
     2629            // 権限:
     2630            // manage_optionsは以下の管理画面設定へのアクセスを許可
     2631            // ・設定 > 一般設定
     2632            // ・設定 > 投稿設定
     2633            // ・設定 > 表示設定
     2634            // ・設定 > ディスカッション
     2635            // ・設定 > パーマリンク設定
     2636            'manage_options',
     2637            // ページを開いたときのURL(slug):
     2638            self::SLUG__HOOK_CONFIG_FORM,
     2639            // メニューに紐づく画面を描画するcallback関数:
     2640            [$this, 'show_hook_config_form']
     2641        );
    17852642    }
    17862643
     
    18562713                <p>
    18572714                    <label for="{$param_stripe_public_key}">公開キー:</label>
    1858                     <input type="password" name="{$param_stripe_public_key}" value="{$stripe_public_key}"/>
     2715                    <input type="text" name="{$param_stripe_public_key}" value="{$stripe_public_key}" style="width:100%"/>
    18592716                </p>
    18602717                <p>
    18612718                    <label for="{$param_stripe_secret_key}">シークレットキー:</label>
    1862                     <input type="password" name="{$param_stripe_secret_key}" value="{$stripe_secret_key}"/>
     2719                    <input type="password" name="{$param_stripe_secret_key}" value="{$stripe_secret_key}" style="width:100%"/>
    18632720                </p>
    18642721                {$submit_button}
     
    19772834            // アンシリアライズした商品情報リストが正しく配列の場合
    19782835            if (is_array($product_list)) {
     2836                // STRIPEのAPIを初期化
     2837                $this->initStripeApi();
     2838               
    19792839                for ($i = 0; $i < count($product_list); $i++) {
    19802840                    if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
    19812841                        // 商品コードが一致する場合
    19822842                        if (is_array($code_list) && in_array($product_list[$i]->code, $code_list)) {
     2843                           
     2844                            // Stripeに商品と価格を新規登録
     2845                            try {
     2846                                // StripeからPlanを取得
     2847                                $plan = \Stripe\Plan::retrieve($product_list[$i]->stripe_plan_id);
     2848                                if (!isset($plan)) {
     2849                                    die('StripeのPlanの削除に失敗しました。');
     2850                                }
     2851                                // Stripeから商品を取得
     2852                                $product = \Stripe\Product::retrieve($plan->product);
     2853                                // 商品情報が存在しない場合
     2854                                if (!isset($product)) {
     2855                                    die('Stripeの商品の取得に失敗しました。');
     2856                                }
     2857                                $plan->delete();
     2858                                $product->delete();
     2859                            } catch (\Stripe\Exception\ApiErrorException $e) {
     2860                                print_r($e);
     2861                                $error = $e->getError();
     2862                                die('Stripeの商品の削除に失敗しました。[ {$error->type} : {$error->message} ]');
     2863                            }
    19832864                            // 削除フラグを立てる
    19842865                            unset($product_list[$i]);
     
    20012882     */
    20022883    function show_product_edit_form() {
    2003        
    20042884        // 商品情報の保存完了メッセージ
    20052885        if (false !== ($complete_message = get_transient(self::TRANSIENT_KEY__SAVE_PRODUCT_INFO))) {
     
    20262906        if (false !== ($invalid_product_button_name = get_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BUTTON_NAME))) {
    20272907            $invalid_product_button_name = self::getNotice($invalid_product_button_name, self::NOTICE_TYPE__ERROR);
     2908        }
     2909        // 商品請求タイミングの不正メッセージ
     2910        if (false !== ($invalid_product_billing_timing = get_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_TIMING))) {
     2911            $invalid_product_billing_timing = self::getNotice($invalid_product_billing_timing, self::NOTICE_TYPE__ERROR);
     2912        }
     2913        // 商品請求間隔の不正メッセージ
     2914        if (false !== ($invalid_product_billing_frequency = get_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_FREQUENCY))) {
     2915            $invalid_product_billing_frequency = self::getNotice($invalid_product_billing_frequency, self::NOTICE_TYPE__ERROR);
     2916        }
     2917        // 商品無料トライアルの不正メッセージ
     2918        if (false !== ($invalid_product_free_trial_days = get_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_FREE_TRIAL_DAYS))) {
     2919            $invalid_product_free_trial_days = self::getNotice($invalid_product_free_trial_days, self::NOTICE_TYPE__ERROR);
    20282920        }
    20292921       
     
    20402932        // 商品ボタン名のパラメータ名
    20412933        $param_product_button_name = self::PARAMETER__PRODUCT_BUTTON_NAME;
     2934        // 商品請求タイミングのパラメータ名
     2935        $param_product_billing_timing = self::PARAMETER__PRODUCT_BILLING_TIMING;
     2936        // 商品請求間隔のパラメータ名
     2937        $param_product_billing_frequency = self::PARAMETER__PRODUCT_BILLING_FREQUENCY;
     2938        // 商品無料トライアルのパラメータ名
     2939        $param_product_free_trial_days = self::PARAMETER__PRODUCT_FREE_TRIAL_DAYS;
     2940       
     2941        // 商品請求タイミングの「分割」のパラメータ値
     2942        $param_value_product_billing_timing_subscription = self::STRIPE_BILLING_TIMING__SUBSCRIPTION;
     2943       
    20422944        // 商品コードをURLクエリー又はTRANSIENTから取得
    20432945        if (($product_code = $_REQUEST[self::PARAMETER__PRODUCT_CODE]) || ($product_code = get_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_CODE))) {
    2044             // 商品コードがあればoptionsテーブルから商品情報を取得
    2045             $product_list = get_option(self::OPTION_KEY__PRODUCT_LIST);
    2046             // 商品情報リストがある場合
    2047             if (!is_null($product_list)) {
    2048                 // 商品情報リストをアンシリアライズ
    2049                 $product_list = unserialize($product_list);
    2050                 // アンシリアライズした商品情報リストが正しく配列の場合
    2051                 if (is_array($product_list)) {
    2052                     for ($i = 0; $i < count($product_list); $i++) {
    2053                         if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
    2054                             // 商品コードが一致する場合
    2055                             if ($product_list[$i]->code == $product_code) {
    2056                                 $product = $product_list[$i];
    2057                             }
    2058                         }
    2059                     }
    2060                 }
    2061             }
    2062         }
    2063         // 商品コードがない場合
    2064         else {
    2065             $product_code_hide_style = 'style="display: none;"';
     2946            // OPTIONSテーブルから商品情報を取得
     2947            $product = $this->getProduct($product_code);
    20662948        }
    20672949       
     
    21162998            }
    21172999        }
     3000        // 商品請求タイミングをoptionsテーブルから取得
     3001        if (false === ($product_billing_timing = get_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_TIMING))) {
     3002            // 登録済み商品情報がある場合
     3003            if (isset($product) && $product) {
     3004                // 登録済み商品情報の商品請求タイミングから取得
     3005                $product_billing_timing = $product->billing_timing;
     3006            }
     3007            // 登録済み商品情報がない場合
     3008            else {
     3009                // デフォルト
     3010                $product_billing_timing = '';
     3011            }
     3012        }
     3013        // 商品請求間隔をoptionsテーブルから取得
     3014        if (false === ($product_billing_frequency = get_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_FREQUENCY))) {
     3015            // 登録済み商品情報がある場合
     3016            if (isset($product) && $product) {
     3017                // 登録済み商品情報の商品請求間隔から取得
     3018                $product_billing_frequency = $product->billing_frequency;
     3019            }
     3020            // 登録済み商品情報がない場合
     3021            else {
     3022                // デフォルト
     3023                $product_billing_frequency = '';
     3024            }
     3025        }
     3026        // 商品無料トライアルをoptionsテーブルから取得
     3027        if (false === ($product_free_trial_days = get_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_FREE_TRIAL_DAYS))) {
     3028            // 登録済み商品情報がある場合
     3029            if (isset($product) && $product) {
     3030                // 登録済み商品情報の商品無料トライアルから取得
     3031                $product_free_trial_days = $product->free_trial_days;
     3032            }
     3033            // 登録済み商品情報がない場合
     3034            else {
     3035                // デフォルト
     3036                $product_free_trial_days = '';
     3037            }
     3038        }
     3039        // StripeのプランID
     3040        if (isset($product) && $product && $product->stripe_plan_id) {
     3041            $stripe_plan_id =
     3042                '<tr><th scope="row"><label>StripのプランID/価格ID:</label></th>' .
     3043                '<td>' . $product->stripe_plan_id . '</td></tr>';
     3044        }
     3045       
     3046        // 商品がある場合
     3047        if (isset($product) && $product) {
     3048            // 定期の場合
     3049            if ($product->billing_timing === self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     3050                $subscription_edit_mode = true;
     3051                $disable_product_price = 'disabled';
     3052                $disable_product_provider_name = 'disabled';
     3053                $disable_product_name = 'disabled';
     3054                $disable_product_currency = 'disabled';
     3055                // $disable_product_button_name = 'disabled';
     3056            }
     3057            $disable_billing_timing = 'disabled';
     3058            $disable_billing_frequency = 'disabled';
     3059            $disable_free_trial_days = 'disabled';
     3060        }
     3061        // 商品がない場合
     3062        else {
     3063            if ($product_billing_timing != self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     3064                $disable_billing_frequency = 'disabled';
     3065                $disable_free_trial_days = 'disabled';
     3066            }
     3067            $product_code_hide_style = 'style="display: none;"';
     3068        }
    21183069       
    21193070        // nonceフィールドを生成・取得
     
    21213072       
    21223073        // STRIPEの通貨リストのOPTIONタグを生成・取得
    2123         $product_currency_options = self::makeHtmlSelectOptions(self::STRIPE_CURRENCIES, $product_currency, 'label');
     3074        $product_currency_options = self::makeHtmlSelectOptions(self::STRIPE_CURRENCIES, $product_currency, self::LABEL);
     3075       
     3076        // 商品請求タイミングリストのRADIOタグを生成・取得
     3077        $product_billing_timing_options = self::makeHtmlSelectOptions(self::STRIPE_BILLING_TIMING_LIST, $product_billing_timing, self::LABEL);
     3078       
     3079        // 商品請求頻度リストのOPTIONタグを生成・取得
     3080        $product_billing_frequency_options = self::makeHtmlSelectOptions(self::STRIPE_BILLING_FREQUENCY_LIST, $product_billing_frequency, self::LABEL);
    21243081       
    21253082        // 送信ボタンを生成・取得
    2126         $submit_button = get_submit_button('保存');
     3083        // if (!isset($product) || !$product) {
     3084            // if ($product->billing_timing !== self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     3085                $submit_button = get_submit_button('保存');
     3086            // }
     3087        // }
     3088       
     3089        $title = '新規登録';
     3090        // 登録済み商品情報がある場合
     3091        if (isset($product) && $product) {
     3092            $title = '変更';
     3093        }
    21273094       
    21283095        // HTMLを出力
    21293096        echo <<< EOM
    21303097            <div class="wrap">
    2131             <h2>新規登録</h2>
     3098            <h2>{$title}</h2>
    21323099            {$complete_message}
    21333100            {$invalid_product_price}
     
    21363103            {$invalid_product_currency}
    21373104            {$invalid_product_button_name}
     3105            {$invalid_product_billing_timing}
     3106            {$invalid_product_billing_frequency}
     3107            {$invalid_product_free_trial_days}
     3108            {$error_stripe_product_register}
    21383109            <form action="" method='post' id="simple-stripe-checkout-product-edit-form">
    21393110                {$nonce_field}
     
    21463117                        <tr>
    21473118                            <th scope="row"><label for="{$param_product_price}">価格:</label></th>
    2148                             <td><input type="text" name="{$param_product_price}" value="{$product_price}" class="regular-text" required/></td>
     3119                            <td>
     3120EOM;
     3121        if (isset($subscription_edit_mode) && $subscription_edit_mode === true) {
     3122            echo $product_price . '<input type="hidden" name="' . $param_product_price . '" value="' . $product_price . '" />';
     3123        } else {
     3124            echo '<input type="text" name="' . $param_product_price . '" value="' . $product_price . '" class="regular-text" required />';
     3125        }
     3126        echo <<< EOM
     3127                            </td>
    21493128                        </tr>
    21503129                        <tr>
    21513130                            <th scope="row"><label for="{$param_product_provider_name}">提供者:</label></th>
    2152                             <td><input type="text" name="{$param_product_provider_name}" value="{$product_provider_name}" class="regular-text" required/></td>
     3131                            <td>
     3132EOM;
     3133        if (isset($subscription_edit_mode) && $subscription_edit_mode === true) {
     3134            echo $product_provider_name . '<input type="hidden" name="' . $param_product_provider_name . '" value="' . $product_provider_name . '" />';
     3135        } else {
     3136            echo '<input type="text" name="' . $param_product_provider_name . '" value="' . $product_provider_name . '" class="regular-text" required />';
     3137        }
     3138        echo <<< EOM
     3139                            </td>
    21533140                        </tr>
    21543141                        <tr>
    21553142                            <th scope="row"><label for="{$param_product_name}">商品名:</label></th>
    2156                             <td><input type="text" name="{$param_product_name}" value="{$product_name}" class="regular-text" required/></td>
     3143                            <td>
     3144EOM;
     3145        if (isset($subscription_edit_mode) && $subscription_edit_mode === true) {
     3146            echo $product_name . '<input type="hidden" name="' . $param_product_name . '" value="' . $product_name . '" />';
     3147        } else {
     3148            echo '<input type="text" name="' . $param_product_name . '" value="' . $product_name . '" class="regular-text" required />';
     3149        }
     3150        echo <<< EOM
     3151                            </td>
    21573152                        </tr>
    21583153                        <tr>
    21593154                            <th scope="row"><label for="{$param_product_currency}">通貨:</label></th>
    2160                             <td><select name="{$param_product_currency}" class="postform">{$product_currency_options}</select></td>
     3155                            <td>
     3156EOM;
     3157        if (isset($subscription_edit_mode) && $subscription_edit_mode === true) {
     3158            echo $product_currency . '<input type="hidden" name="' . $param_product_currency . '" value="' . $product_currency . '" />';
     3159        } else {
     3160            echo '<select name="' . $param_product_currency . '" class="postform">' . $product_currency_options . '</select>';
     3161        }
     3162        echo <<< EOM
     3163                            </td>
    21613164                        </tr>
    21623165                        <tr>
    21633166                            <th scope="row"><label for="{$param_product_button_name}">ボタンの名前:</label></th>
    2164                             <td><input type="text" name="{$param_product_button_name}" value="{$product_button_name}" class="regular-text" required/></td>
     3167                            <td><input type="text" name="{$param_product_button_name}" value="{$product_button_name}" class="regular-text" required /></td>
    21653168                        </tr>
     3169                        <tr>
     3170                            <th scope="row"><label for="{$param_product_billing_timing}">請求タイミング:</label></th>
     3171                            <td><select name="{$param_product_billing_timing}" class="postform" {$disable_billing_timing} onchange="
     3172                              var elmBillingFrequency = document.getElementById('{$param_product_billing_frequency}');
     3173                              var elmFreeTrialDays = document.getElementById('{$param_product_free_trial_days}');
     3174                              if (this.value != '{$param_value_product_billing_timing_subscription}') {
     3175                                elmBillingFrequency.disabled = true;
     3176                                elmBillingFrequency.value = null;
     3177                                elmFreeTrialDays.disabled = true;
     3178                                elmFreeTrialDays.value = null;
     3179                              } else {
     3180                                elmBillingFrequency.disabled = false;
     3181                                elmFreeTrialDays.disabled = false;
     3182                              }
     3183                            "><option></option>{$product_billing_timing_options}</select></td>
     3184                        </tr>
     3185                        <tr>
     3186                            <th scope="row"><label for="{$param_product_billing_frequency}">請求間隔:</label></th>
     3187                            <td><select id="{$param_product_billing_frequency}" name="{$param_product_billing_frequency}" class="postform" {$disable_billing_frequency}><option></option>{$product_billing_frequency_options}</select></td>
     3188                        </tr>
     3189                        <tr>
     3190                            <th scope="row"><label for="{$param_product_free_trial_days}">無料トライアル:</label></th>
     3191                            <td>
     3192                                <input type="number" step="1" min="0" max="365" id="{$param_product_free_trial_days}" name="{$param_product_free_trial_days}" value="{$product_free_trial_days}" class="regular-text" {$disable_free_trial_days}/>日<br/>
     3193                                ※すぐ開始の場合は0日で設定してください。
     3194                             </td>
     3195                        </tr>
     3196                        {$stripe_plan_id}
    21663197                    </tbody>
    21673198                </table>
     
    21923223                // 商品ボタン名をPOSTから取得
    21933224                $product_button_name = trim(sanitize_text_field($_POST[self::PARAMETER__PRODUCT_BUTTON_NAME]));
     3225                // 商品請求タイミングをPOSTから取得
     3226                $product_billing_timing = trim(sanitize_text_field($_POST[self::PARAMETER__PRODUCT_BILLING_TIMING]));
     3227                // 商品請求間隔をPOSTから取得
     3228                $product_billing_frequency = trim(sanitize_text_field($_POST[self::PARAMETER__PRODUCT_BILLING_FREQUENCY]));
     3229                // 商品無料トライアルをPOSTから取得
     3230                $product_free_trial_days = trim(sanitize_text_field($_POST[self::PARAMETER__PRODUCT_FREE_TRIAL_DAYS]));
    21943231                $valid = true;
    21953232                // 商品価格が正しくない場合
     
    22303267                    $valid = false;
    22313268                }
     3269                // 新規の場合(商品コードがない場合)
     3270                if ($product_code <= 0) {
     3271                    // 商品請求タイミングが正しくない場合
     3272                    if (strlen($product_billing_timing) === 0) {
     3273                        // 商品請求タイミングの設定し直しを促すメッセージをTRANSIENTに5秒間保持
     3274                        set_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_TIMING, "商品請求タイミングが正しくありません。", self::TRANSIENT_TIME_LIMIT);
     3275                        // 有効フラグをFalse
     3276                        $valid = false;
     3277                    }
     3278                    if ($product_billing_timing === self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     3279                        // 商品請求間隔が正しくない場合
     3280                        if (strlen($product_billing_frequency) === 0) {
     3281                            // 商品請求間隔の設定し直しを促すメッセージをTRANSIENTに5秒間保持
     3282                            set_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_FREQUENCY, "商品請求間隔が正しくありません。", self::TRANSIENT_TIME_LIMIT);
     3283                            // 有効フラグをFalse
     3284                            $valid = false;
     3285                        }
     3286                        // 商品無料トライアルが正しくない場合
     3287                        if (strlen($product_free_trial_days) === 0) {
     3288                            // 商品無料トライアルの設定し直しを促すメッセージをTRANSIENTに5秒間保持
     3289                            set_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_FREE_TRIAL_DAYS, "商品無料トライアル日数が正しくありません。", self::TRANSIENT_TIME_LIMIT);
     3290                            // 有効フラグをFalse
     3291                            $valid = false;
     3292                        }
     3293                    }
     3294                }
    22323295                // 有効フラグがTrueの場合(商品情報が正しい場合)
    22333296                if ($valid) {
     
    22563319                                if ($product_list[$i]->code == $product_code) {
    22573320                                    // 商品情報の各値をセット
    2258                                     $product_list[$i]->price         = $product_price;
    2259                                     $product_list[$i]->provider_name = $product_provider_name;
    2260                                     $product_list[$i]->name          = $product_name;
    2261                                     $product_list[$i]->currency      = $product_currency;
    2262                                     $product_list[$i]->button_name   = $product_button_name;
     3321                                    $product_list[$i]->price                     = $product_price;
     3322                                    $product_list[$i]->provider_name             = $product_provider_name;
     3323                                    $product_list[$i]->name                      = $product_name;
     3324                                    $product_list[$i]->currency                  = $product_currency;
     3325                                    $product_list[$i]->button_name               = $product_button_name;
     3326                                    // $product_list[$i]->billing_timing    = $product_billing_timing;
     3327                                    // $product_list[$i]->billing_frequency = $product_billing_frequency;
     3328                                    // $product_list[$i]->free_trial_days   = $product_free_trial_days;
    22633329                                    // 更新対象があったので有効フラグをTRUEに戻す
    22643330                                    $valid = true;
     
    22703336                    // 新規の場合(商品コードがない場合)
    22713337                    else {
    2272                         // 最も大きい商品コードを取得
    2273                         $max_product_code = 0;
    2274                         for ($i = 0; $i < count($product_list); $i++) {
    2275                             if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
    2276                                 if ($product_list[$i]->code > $max_product_code) {
    2277                                     $max_product_code = $product_list[$i]->code;
     3338                        // 定期の場合
     3339                        if ($product_billing_timing === self::STRIPE_BILLING_TIMING__SUBSCRIPTION) {
     3340                            // STRIPEのAPIを初期化
     3341                            $this->initStripeApi();
     3342                            // Stripeに商品と価格を新規登録
     3343                            try {
     3344                                $stripe_product = \Stripe\Product::create([
     3345                                    'name' => $product_name,
     3346                                ]);
     3347                                if ($product_billing_frequency === self::STRIPE_BILLING_FREQUENCY__MONTHLY) {
     3348                                    $recurring_interval = 'month';
     3349                                } else if ($product_billing_frequency === self::STRIPE_BILLING_FREQUENCY__YEARLY) {
     3350                                    $recurring_interval = 'year';
     3351                                }
     3352                                $stripe_plan = \Stripe\Plan::create([
     3353                                    'amount' => $product_price,
     3354                                    'currency' => $product_currency,
     3355                                    'interval' => $recurring_interval,
     3356                                    'product' => $stripe_product->id,
     3357                                    'trial_period_days' => $product_free_trial_days,
     3358                                ]);
     3359                            } catch (\Stripe\Exception\ApiErrorException $e) {
     3360                                // ユーザが入力した商品無料トライアルをTRANSIENTに5秒間保持
     3361                                $error = $e->getError();
     3362                                set_transient(self::TRANSIENT_KEY__ERROR_STRIPE_PRODUCT_REGISTER, "Stripeへの商品登録に失敗しました。<br>[{$error->type}]<br>{$error->message}", self::TRANSIENT_TIME_LIMIT);
     3363                                $valid = false;
     3364                            }
     3365                            // StripeにWebhookを登録
     3366                            $this->registerWebhook();
     3367                        }
     3368                        // print_r($stripe_plan);
     3369                        // die(' finish ');
     3370                        if ($valid) {
     3371                            /*
     3372                            $stripe->prices->create([
     3373                              'unit_amount' => 2000,
     3374                              'currency' => 'jpy',
     3375                              'recurring' => ['interval' => 'month'],
     3376                              'product' => 'prod_HFwiPNJo6Kgp99',
     3377                            ]);
     3378                            */
     3379                            // 最も大きい商品コードを取得
     3380                            $max_product_code = 0;
     3381                            for ($i = 0; $i < count($product_list); $i++) {
     3382                                if ($product_list[$i] instanceof SimpleStripeCheckout_Product) {
     3383                                    if ($product_list[$i]->code > $max_product_code) {
     3384                                        $max_product_code = $product_list[$i]->code;
     3385                                    }
    22783386                                }
    22793387                            }
     3388                            // 商品情報の各値をセット
     3389                            $product = new SimpleStripeCheckout_Product();
     3390                            $product->code              = $max_product_code + 1;
     3391                            $product->price             = $product_price;
     3392                            $product->provider_name     = $product_provider_name;
     3393                            $product->name              = $product_name;
     3394                            $product->currency          = $product_currency;
     3395                            $product->button_name       = $product_button_name;
     3396                            $product->billing_timing    = $product_billing_timing;
     3397                            $product->billing_frequency = $product_billing_frequency;
     3398                            $product->free_trial_days   = $product_free_trial_days;
     3399                            $product->stripe_plan_id    = $stripe_plan->id;
     3400                            // 商品情報リストに追加
     3401                            $product_list[] = $product;
    22803402                        }
    2281                         // 商品情報の各値をセット
    2282                         $product = new SimpleStripeCheckout_Product();
    2283                         $product->code          = $max_product_code + 1;
    2284                         $product->price         = $product_price;
    2285                         $product->provider_name = $product_provider_name;
    2286                         $product->name          = $product_name;
    2287                         $product->currency      = $product_currency;
    2288                         $product->button_name   = $product_button_name;
    2289                         // 商品情報リストに追加
    2290                         $product_list[] = $product;
    22913403                    }
    22923404                    // 有効フラグがTrueの場合(商品情報の保存が完了した場合)
     
    23083420                        // (一応)商品ボタン名の不正メッセージをTRANSIENTから削除
    23093421                        delete_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BUTTON_NAME);
     3422                        // (一応)商品請求タイミングの不正メッセージをTRANSIENTから削除
     3423                        delete_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_TIMING);
     3424                        // (一応)商品請求間隔の不正メッセージをTRANSIENTから削除
     3425                        delete_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_BILLING_FREQUENCY);
     3426                        // (一応)商品無料トライアルの不正メッセージをTRANSIENTから削除
     3427                        delete_transient(self::TRANSIENT_KEY__INVALID_PRODUCT_FREE_TRIAL_DAYS);
    23103428                       
    23113429                        // (一応)ユーザが入力した商品価格をTRANSIENTから削除
     
    23193437                        // (一応)ユーザが入力した商品ボタン名をTRANSIENTから削除
    23203438                        delete_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BUTTON_NAME);
     3439                        // (一応)ユーザが入力した商品請求タイミングをTRANSIENTから削除
     3440                        delete_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_TIMING);
     3441                        // (一応)ユーザが入力した商品請求間隔をTRANSIENTから削除
     3442                        delete_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_FREQUENCY);
     3443                        // (一応)ユーザが入力した商品無料トライアルをTRANSIENTから削除
     3444                        delete_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_FREE_TRIAL_DAYS);
     3445                       
     3446                        // (一応)STRIPE商品登録失敗メッセージをTRANSIENTから削除
     3447                        delete_transient(self::TRANSIENT_KEY__ERROR_STRIPE_PRODUCT_REGISTER);
    23213448                    }
    23223449                }
     
    23333460                    // ユーザが入力した商品ボタン名をTRANSIENTに5秒間保持
    23343461                    set_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BUTTON_NAME, $product_button_name, self::TRANSIENT_TIME_LIMIT);
    2335 
    2336                     // (一応)商品情報の保存完了メッセージを削除
    2337                     delete_transient(self::TRANSIENT_KEY__SAVE_PRODUCT_INFO);
     3462                    // ユーザが入力した商品請求タイミングをTRANSIENTに5秒間保持
     3463                    set_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_TIMING, $product_billing_timing, self::TRANSIENT_TIME_LIMIT);
     3464                    // ユーザが入力した商品請求間隔をTRANSIENTに5秒間保持
     3465                    set_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_BILLING_FREQUENCY, $product_billing_frequency, self::TRANSIENT_TIME_LIMIT);
     3466                    // ユーザが入力した商品無料トライアルをTRANSIENTに5秒間保持
     3467                    set_transient(self::TRANSIENT_KEY__TEMP_PRODUCT_FREE_TRIAL_DAYS, $product_free_trial_days, self::TRANSIENT_TIME_LIMIT);
    23383468                }
    23393469                // 設定画面にリダイレクト
     
    25593689    }
    25603690
     3691    /**
     3692     * サブメニュー「Webhook設定」押下時の画面を表示するcallback関数
     3693     */
     3694    function show_hook_config_form() {
     3695        // メール設定の保存完了メッセージ
     3696        if (false !== ($complete_message = get_transient(self::TRANSIENT_KEY__SAVE_HOOK_CONFIG))) {
     3697            $complete_message = self::getNotice($complete_message, self::NOTICE_TYPE__SUCCESS);
     3698        }
     3699       
     3700        // nonceフィールドを生成・取得
     3701        $nonce_field = wp_nonce_field(self::CREDENTIAL_ACTION__HOOK_CONFIG, self::CREDENTIAL_NAME__HOOK_CONFIG, true, false);
     3702       
     3703        // Home URL
     3704        $home_url = home_url();
     3705       
     3706        // Webhook URL
     3707        $expected_webhook_url = $home_url . '/?' . self::SLUG__PAY_SUBSCRIPTION . '=true';
     3708       
     3709        // STRIPEのAPIを初期化
     3710        $this->initStripeApi();
     3711       
     3712        // StripeのWebhookに登録されているか
     3713        $has_registered_webhook = false;
     3714        try {
     3715            $webhook_list = \Stripe\WebhookEndpoint::all();
     3716            if (isset($webhook_list) && $webhook_list->data && is_array($webhook_list->data)) {
     3717                for ($i = 0; $i < count($webhook_list->data); $i++) {
     3718                    if ($webhook_list->data[$i]->url === $expected_webhook_url) {
     3719                        $has_registered_webhook = true;
     3720                    }
     3721                }
     3722            }
     3723        } catch (Exception $e) {
     3724            die('StripeのWebhook情報を取得できません。');
     3725        }
     3726       
     3727        // 登録ボタンを生成・取得
     3728        if (!isset($has_registered_webhook) || $has_registered_webhook !== true) {
     3729            $submit_button = get_submit_button('登録');
     3730        } else {
     3731            $submit_button = $expected_webhook_url;
     3732        }
     3733       
     3734        // HTMLを出力
     3735        echo <<< EOM
     3736            <div class="wrap">
     3737            <h2>Webhook設定</h2>
     3738            {$complete_message}
     3739            <form action="" method='post' id="simple-stripe-checkout-hook-config-form">
     3740                {$nonce_field}
     3741                <table class="form-table" role="presentation">
     3742                    <tbody>
     3743                        <tr>
     3744                            <th scope="row"><label for="home_url">Home URL:</label></th>
     3745                            <td>{$home_url}</td>
     3746                        </tr>
     3747                        <tr>
     3748                            <th scope="row"><label for="stripe_webhook_url">Stripe Webhook URL:</label></th>
     3749                            <td>
     3750                                <input type="hidden" name="dummy" value="dummy" />
     3751                                {$submit_button}
     3752                            </td>
     3753                        </tr>
     3754                    </tbody>
     3755                </table>
     3756            </form>
     3757            </div>
     3758EOM;
     3759    }
     3760
     3761    /**
     3762     * Webhook設定を保存するcallback関数
     3763     */
     3764    function save_hook_config() {
     3765        // nonceで設定したcredentialをPOST受信した場合
     3766        if (isset($_POST[self::CREDENTIAL_NAME__HOOK_CONFIG]) && $_POST[self::CREDENTIAL_NAME__HOOK_CONFIG]) {
     3767            // nonceで設定したcredentialのチェック結果が問題ない場合
     3768            if (check_admin_referer(self::CREDENTIAL_ACTION__HOOK_CONFIG, self::CREDENTIAL_NAME__HOOK_CONFIG)) {
     3769               
     3770                // STRIPEのAPIを初期化
     3771                $this->initStripeApi();
     3772               
     3773                // StripeにWebhookを登録
     3774                $this->registerWebhook();
     3775               
     3776                // 保存が完了したら、完了メッセージをTRANSIENTに5秒間保持
     3777                set_transient(self::TRANSIENT_KEY__SAVE_HOOK_CONFIG, "StripeにWebhookを登録しました。", self::TRANSIENT_TIME_LIMIT);
     3778               
     3779                // 設定画面にリダイレクト
     3780                wp_safe_redirect(menu_page_url(self::SLUG__HOOK_CONFIG_FORM, false), 303);
     3781            }
     3782        }
     3783    }
     3784   
     3785    /**
     3786     * StripeにWebhookを登録
     3787     */
     3788    function registerWebhook() {
     3789        $expected_webhook_url = home_url() . '/?' . self::SLUG__PAY_SUBSCRIPTION . '=true';
     3790        // StripeのWebhookに登録されているか
     3791        $has_registered_webhook = false;
     3792        try {
     3793            $webhook_list = \Stripe\WebhookEndpoint::all();
     3794            if (isset($webhook_list) && $webhook_list->data && is_array($webhook_list->data)) {
     3795                for ($i = 0; $i < count($webhook_list->data); $i++) {
     3796                    if ($webhook_list->data[$i]->url === $expected_webhook_url) {
     3797                        $has_registered_webhook = true;
     3798                    }
     3799                }
     3800            }
     3801        } catch (\Stripe\Exception\ApiErrorException $e) {
     3802            $error = $e->getError();
     3803            die('StripeのWebhook情報を取得できません。 [' . $error->type . ':' . $error->message . ']');
     3804        }
     3805        // StripeにWebhookを登録
     3806        try {
     3807            if ($has_registered_webhook !== true) {
     3808                $webhook_list = \Stripe\WebhookEndpoint::create(array(
     3809                    'url' => home_url() . '/?' . self::SLUG__PAY_SUBSCRIPTION . '=true',
     3810                    'enabled_events' => array(
     3811                      'invoice.payment_succeeded',
     3812                    ),
     3813                ));
     3814            }
     3815        } catch (\Stripe\Exception\ApiErrorException $e) {
     3816            $error = $e->getError();
     3817            die('StripeにWebhookを登録できません。 [' . $error->type . ':' . $error->message . ']');
     3818        }
     3819    }
     3820
    25613821} // end of class
    25623822
Note: See TracChangeset for help on using the changeset viewer.