7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

noteなどを読んでいると、記事末尾に「いいなと思ったら応援しよう!」という文言を見かけることがあります。いわゆる投げ銭機能です。

見ず知らずの人から投げ銭をもらうことを不安に感じつつも、「サポートしてもらえて羨ましい…」 と感じる気持ちもあります。

それなら自分がワードプレスで運営しているブログ実装しちゃえ!と、PAY.JPを活用して投げ銭機能を実装してみました!

noteなどでよく見かける投げ銭機能

ブログサービスとして日本で多く利用されているnoteの記事を読んでいると記事末尾に 「チップで応援する」 という表示を見かけることが多いです。

これはサポート(チップ)機能という、気に入った著者を支援できるいわゆる「投げ銭」機能です。

image.png

noteはあまり詳しくないですが、SNS等をみると、実際に投げ銭で支援されている人もいるようです。

私はワードプレスでブログを運営しており、note標準機能として備わっているこうしたクリエイターのサポーター機能などを羨ましく感じていました。

ワードプレスで使える投げ銭サービスはあれど…

もちろんワードプレスでも投げ銭サービスを導入することは可能です。

image.png

投げ銭サービスが提供しているワードプレスのプラグイン機能を利用することで、比較的簡単に導入できます。

ただネックとなるのは決済手数料です。

例えば、ワードプレスの投げ銭のプラグインとしてよく使われているサービスの場合、以下の手数料でした。

  1. 販売手数料15%
  2. 振込手数料が300円

仮に1,000円の投げ銭を受けた場合、受け取れる金額は以下の通りです。

  • 手数料合計:(販売手数料15%)150円 + (振込手数料)300円 = 450円
  • 受け取り額:1,000円 - 450円 = 550円

残念ながら1,000円支援をされても、55%しか受け取れません。

投げ銭が多くなるほど、手にする割合が増えるものの、スケールメリットが効くほど投げ銭が得られることはごく稀かです。

もちろん決済機能は重要な処理なので、そうした金額が妥当という面もあります。

しかし利用者からするとやはり、できるだけ多く受け取りたいという気持ちが湧きます。

PAY.JPなら手数料も格安!

しかし、PAY.JPなら手数料もリーズナブルです!

スタンダードプランなら初期費用や月額費用もかからず無料です。

手数料は決済手数料3.3%と振込手数料の250円となっています。

Snipaste_2025-12-18_00-27-12.png
PAY.JPの料金体系のページより

先ほどの事例と同じように投げ銭が1,000円として計算すると、以下の通りです。

  • 手数料合計:(決済手数料3.3%)33円 + (振込手数料)250円 = 283円
  • 受け取り額:1,000円 - 283円 = 717円

投げ銭してもらったユーザーからの気持ちをしっかり受け取ることができます。

スタンダードプラン以外にも企業向けにビジネスプランやエンタープライズプランもあります。

これらは月額費用が発生するものの、その分決済手数料が安くなっています。

月商400万円以上〜の場合はビジネスプランやエンタープライズプランの方が支出を抑えられるとのことです。

個人や小規模事業だけでなく、中規模さらに大企業でも導入しやすい決済サービスになっています。

ワードプレスに投げ銭機能を実装してみた

PAY.JPでは、現在ワードプレスの公式プラグイン等は提供されておりません。

そこで、自分が運営しているワードプレスにPAY.JPを使って投げ銭機能を実装してみました。

PAY.JPを導入するワードプレスの構成

導入するワードプレスサイトの環境は以下の通りです。

  • エックスサーバーのレンタルサーバー(共用サーバー)を利用
  • 簡単インストール機能でワードプレスをインストール
  • ワードプレスのテーマはCocoon

個人でのワードプレス構築としてはよくある構成となっています。

この共用レンタルサーバー+CocoonのワードプレスにPAY.JPを使い投げ銭を実装していきます。

PAY.JP側の利用登録とテスト用キー発行

PAY.JPを利用するにはアカウント登録して、APIキーを発行する必要があります。

まず、PAY.JPのページにアクセスし、「無料アカウント登録」を選択します。

image.png

メールアドレスとパスワードを入力し、利用規約を確認して同意した上してアカウントを作成します。

Snipaste_2025-12-18_00-36-29.png

メールアドレスによる認証を行うと、アカウントが発行され、ビジネス情報を入力すると本番利用が開始できます。

ただ、テスト環境での利用の場合はビジネス情報の入力は不要です。

今回はあくまでもワードプレスに投げ銭機能をPAY.JPでテスト実装するため、ビジネス情報は登録せずに進めます。

PAY.JP管理画面の左メニューにある「API設定」を選択すると、テスト用のAPIキーが表示されます。

image.png

これらのAPIキーをコピペして実装で利用していきます。

今回はテスト環境のAPIキーですが、APIキーの漏えいは重大なセキュリティインシデントです。暗号化しておくなど厳重に保管しておきましょう。

PAY.JPの実装をAIコーディング

なお、今回は自分ではPAY.JP実装コードを自力で書いていません。

生成AI(Gemini 3.0 Pro)を利用してAIコーディングで実装しました。

Geminiに以下のプロンプトでPAY.JPによる投げ銭機能の実装方法の説明と実装で必要となるコードを生成してもらいました。

PAY.JPを使って、Wordpressに投げ銭機能を実装したいです。
投げ銭モジュールを設置したい記事にショートコードを挿入して、ショートコードを呼び出して、特定記事に投げ銭を実装する仕組みです。
そのために必要なコードとAPIキー等の埋め込み方法など解説してください。

かなりざっくりとしたプロンプトによる指示でしたが、Gemini3.0 proは実装の流れから実装するコード、実装手順までを出力してくれました。

◎実装の流れ

  • Step 1: PAY.JP PHPライブラリをレンタルサーバーにインストール
  • Step 2: WordPressに生成したコードを追加する
  • Step 3: ショートコードの挿入

まず、Step1のPAY.JPのPHPライブラリ「payjp/payjp-php」をレンタルサーバーにインストールします。

サーバーサイドでPAY.JPのAPIを叩くために、公式のPHPライブラリを使用します。
WordPressのルートディレクトリ(`wp-config.php`などがある場所)で、Composerを使ってインストールするのが最も簡単で推奨される方法です。

もしサーバーにSSHで接続できるなら、以下のコマンドを実行します。

composer require payjp/payjp-php

これにより、`vendor`というディレクトリが作成され、ライブラリがインストールされます。

※ もしComposerが使えない環境の場合は、ライブラリを[GitHubからダウンロード](https://github.com/payjp/payjp-php)し、手動でテーマフォルダ内に設置して`require`することも可能ですが、管理が煩雑になるためComposerを強く推奨します。

続いてStep2ではワードプレステーマのfunctions.phpや新規のJavascriptの作成、CSSファイルの配置が指示されました。

Cocoonの子テーマのfunctions.phpに以下のコードを追記します。

<?php
// functions.php

// --- PAY.JP APIキーを設定 ---
// 本番環境ではwp-config.phpへの記述を推奨します
define('PAYJP_PUBLIC_KEY', 'ここにあなたの公開鍵(pk_test_...)');
define('PAYJP_SECRET_KEY', 'ここにあなたの秘密鍵(sk_test_...)');

// Composerのオートローダーを読み込む
// パスはご自身の環境に合わせてください
require_once( get_stylesheet_directory() . '/../../../vendor/autoload.php'); // 例: /var/www/html/vendor/autoload.php

/**
 * 必要なCSSとJSを読み込む
 */
function payjp_tipping_enqueue_scripts() {
    // 記事ページでのみ読み込む
    if (is_single()) {
        // PAY.JP公式JSライブラリ
        wp_enqueue_script('payjp-js', 'https://js.pay.jp/v2/pay.js', array(), null, true);

        // 自作のJSファイル
        wp_enqueue_script(
            'payjp-tipping-js',
            get_stylesheet_directory_uri() . '/payjp-tipping.js',
            array('jquery', 'payjp-js'), // jQueryとpayjp-jsに依存
            filemtime(get_stylesheet_directory() . '/payjp-tipping.js'),
            true
        );

        // 自作のCSSファイル
        wp_enqueue_style(
            'payjp-tipping-css',
            get_stylesheet_directory_uri() . '/payjp-tipping.css',
            array(),
            filemtime(get_stylesheet_directory() . '/payjp-tipping.css')
        );

        // PHPの変数をJSに渡す(公開鍵やAjaxのエンドポイントなど)
        wp_localize_script('payjp-tipping-js', 'payjp_tipping_vars', array(
            'public_key' => PAYJP_PUBLIC_KEY,
            'ajax_url'   => admin_url('admin-ajax.php'),
            'nonce'      => wp_create_nonce('payjp-tipping-nonce'),
        ));
    }
}
add_action('wp_enqueue_scripts', 'payjp_tipping_enqueue_scripts');


/**
 * ショートコード [tip_button] を登録 (修正版)
 */
function payjp_tip_button_shortcode($atts) {
    // ショートコードから渡された属性が配列であることを保証する
    $atts = (array) $atts;

    // デフォルト値とショートコードの属性をマージする
    // 変数名を $args に変更し、元の $atts との混同を避ける
    $args = shortcode_atts(array(
        'amounts' => '100,300,500,1000', // カンマ区切りで金額の選択肢を指定
        'text'    => 'この記事の作者に投げ銭する',
    ), $atts, 'tip_button');

    // 属性から値を取り出して変数に格納する
    $amounts = array_map('intval', explode(',', $args['amounts']));
    $button_text = esc_html($args['text']);

    // HTMLの出力を開始
    ob_start();
    ?>
    <div class="tip-button-wrapper">
        <button id="show-tip-modal" class="tip-button"><?php echo $button_text; ?></button>
    </div>

    <!-- 投げ銭モーダル -->
    <div id="tip-modal-overlay" style="display: none;">
        <div id="tip-modal">
            <h3>投げ銭ありがとうございます!</h3>
            <p>金額を選択し、カード情報を入力してください。</p>

            <form id="payjp-tip-form" method="post">
                <div class="tip-amount-selector">
                    <?php foreach ($amounts as $amount) : ?>
                        <label>
                            <input type="radio" name="tip_amount" value="<?php echo $amount; ?>" <?php if ($amount === $amounts[0]) echo 'checked'; ?>>
                            <?php echo number_format($amount); ?></label>
                    <?php endforeach; ?>
                    <label>
                        <input type="radio" name="tip_amount" value="custom"> その他
                    </label>
                    <input type="number" id="custom-amount-input" name="custom_amount" min="50" placeholder="50円〜" style="display: none;">
                </div>

                <!-- PAY.JPの入力フォームがここに生成される -->
                <div id="card-element"></div>

                <div id="card-errors" role="alert"></div>

                <button type="submit" id="tip-submit-button">この金額で支援する</button>
            </form>
            <button id="close-tip-modal">閉じる</button>
            <div id="tip-processing-overlay" style="display:none;">処理中...</div>
        </div>
    </div>
    <?php
    return ob_get_clean();
}
add_shortcode('tip_button', 'payjp_tip_button_shortcode');


/**
 * Ajaxリクエストを処理して決済を実行する
 */
function handle_payjp_payment() {
    // nonceをチェックしてセキュリティを確保
    check_ajax_referer('payjp-tipping-nonce', 'nonce');

    // 送られてきたデータをサニタイズ
    $token  = isset($_POST['token']) ? sanitize_text_field($_POST['token']) : '';
    $amount = isset($_POST['amount']) ? intval($_POST['amount']) : 0;

    if (empty($token) || $amount < 50) { // PAY.JPの最低決済額は50円
        wp_send_json_error(array('message' => '無効なリクエストです。'));
        return;
    }

    try {
        // PAY.JPの秘密鍵をセット
        \Payjp\Payjp::setApiKey(PAYJP_SECRET_KEY);

        // 決済(Charge)を作成
        $charge = \Payjp\Charge::create(array(
            'card'     => $token,
            'amount'   => $amount,
            'currency' => 'jpy',
            'description' => 'WordPressからの投げ銭 (' . get_permalink($_POST['post_id']) . ')'
        ));

        // 成功した場合
        wp_send_json_success(array('message' => 'ご支援ありがとうございます!決済が完了しました。'));

    } catch (\Payjp\Error\Card $e) {
        // カードエラーの場合 (残高不足、有効期限切れなど)
        $body = $e->getJsonBody();
        $err  = $body['error'];
        wp_send_json_error(array('message' => 'カードエラー: ' . $err['message']));
    } catch (\Exception $e) {
        // その他のAPIエラー
        wp_send_json_error(array('message' => '決済処理中にエラーが発生しました。しばらくしてから再度お試しください。'));
    }
}
// ログインユーザー、非ログインユーザー両方からのAjaxリクエストに対応
add_action('wp_ajax_process_tip_payment', 'handle_payjp_payment');
add_action('wp_ajax_nopriv_process_tip_payment', 'handle_payjp_payment');

今回はテスト実装のためfunctions.phpに直接APIキーを記述していますが、APIキーのような機密情報は wp-config.php に記述して参照する方が安全です。

次に子テーマと同じディレクトリにpayjp-tipping.jsを新規作成して配置します。

jQuery(function ($) {
    // PAY.JPの初期化
    if (typeof Payjp === 'undefined') {
        return;
    }
    const payjp = Payjp(payjp_tipping_vars.public_key);
    const elements = payjp.elements();
    const cardElement = elements.create('card');
    
    // ショートコードが存在する場合のみ実行
    if ($('#show-tip-modal').length > 0) {
        cardElement.mount('#card-element');
    }

    // モーダル表示・非表示
    $('#show-tip-modal').on('click', function () {
        $('#tip-modal-overlay').fadeIn();
    });

    $('#close-tip-modal, #tip-modal-overlay').on('click', function (e) {
        if (e.target.id === 'close-tip-modal' || e.target.id === 'tip-modal-overlay') {
            $('#tip-modal-overlay').fadeOut();
        }
    });
    $('#tip-modal').on('click', function (e) {
        e.stopPropagation();
    });

    // 金額選択のロジック
    $('input[name="tip_amount"]').on('change', function() {
        if ($(this).val() === 'custom') {
            $('#custom-amount-input').show().focus();
        } else {
            $('#custom-amount-input').hide();
        }
    });


    // フォーム送信時の処理
    $('#payjp-tip-form').on('submit', function (e) {
        e.preventDefault(); // デフォルトのフォーム送信を止める

        $('#tip-processing-overlay').show();
        $('#tip-submit-button').prop('disabled', true);

        // トークンを作成
        payjp.createToken(cardElement).then(function (response) {
            if (response.error) {
                // エラー処理
                $('#card-errors').text(response.error.message);
                $('#tip-processing-overlay').hide();
                $('#tip-submit-button').prop('disabled', false);
            } else {
                // 成功したらトークンをサーバーに送信
                const token = response.id;
                sendTokenToServer(token);
            }
        });
    });

    // トークンをサーバーに送信する関数
    function sendTokenToServer(token) {
        let amount = $('input[name="tip_amount"]:checked').val();
        if (amount === 'custom') {
            amount = $('#custom-amount-input').val();
        }

        $.ajax({
            type: 'POST',
            url: payjp_tipping_vars.ajax_url,
            data: {
                action: 'process_tip_payment',
                nonce: payjp_tipping_vars.nonce,
                token: token,
                amount: amount,
                post_id: $('body').hasClass('single') ? $('article').attr('id').replace('post-', '') : 0 // 記事IDを取得
            },
            dataType: 'json',
            success: function (response) {
                if (response.success) {
                    alert(response.data.message);
                    $('#tip-modal-overlay').fadeOut();
                } else {
                    alert('エラー: ' + response.data.message);
                }
            },
            error: function () {
                alert('通信エラーが発生しました。');
            },
            complete: function() {
                $('#tip-processing-overlay').hide();
                $('#tip-submit-button').prop('disabled', false);
                cardElement.clear(); // フォームをクリア
            }
        });
    }
});

最後にpayjp-tipping.cssを新規作成し、下記のCSSファイルを配置します。

jQuery(function ($) {
    // PAY.JPの初期化
    if (typeof Payjp === 'undefined') {
        return;
    }
    const payjp = Payjp(payjp_tipping_vars.public_key);
    const elements = payjp.elements();
    const cardElement = elements.create('card');
    
    // ショートコードが存在する場合のみ実行
    if ($('#show-tip-modal').length > 0) {
        cardElement.mount('#card-element');
    }

    // モーダル表示・非表示
    $('#show-tip-modal').on('click', function () {
        $('#tip-modal-overlay').fadeIn();
    });

    $('#close-tip-modal, #tip-modal-overlay').on('click', function (e) {
        if (e.target.id === 'close-tip-modal' || e.target.id === 'tip-modal-overlay') {
            $('#tip-modal-overlay').fadeOut();
        }
    });
    $('#tip-modal').on('click', function (e) {
        e.stopPropagation();
    });

    // 金額選択のロジック
    $('input[name="tip_amount"]').on('change', function() {
        if ($(this).val() === 'custom') {
            $('#custom-amount-input').show().focus();
        } else {
            $('#custom-amount-input').hide();
        }
    });


    // フォーム送信時の処理
    $('#payjp-tip-form').on('submit', function (e) {
        e.preventDefault(); // デフォルトのフォーム送信を止める

        $('#tip-processing-overlay').show();
        $('#tip-submit-button').prop('disabled', true);

        // トークンを作成
        payjp.createToken(cardElement).then(function (response) {
            if (response.error) {
                // エラー処理
                $('#card-errors').text(response.error.message);
                $('#tip-processing-overlay').hide();
                $('#tip-submit-button').prop('disabled', false);
            } else {
                // 成功したらトークンをサーバーに送信
                const token = response.id;
                sendTokenToServer(token);
            }
        });
    });

    // トークンをサーバーに送信する関数
    function sendTokenToServer(token) {
        let amount = $('input[name="tip_amount"]:checked').val();
        if (amount === 'custom') {
            amount = $('#custom-amount-input').val();
        }

        $.ajax({
            type: 'POST',
            url: payjp_tipping_vars.ajax_url,
            data: {
                action: 'process_tip_payment',
                nonce: payjp_tipping_vars.nonce,
                token: token,
                amount: amount,
                post_id: $('body').hasClass('single') ? $('article').attr('id').replace('post-', '') : 0 // 記事IDを取得
            },
            dataType: 'json',
            success: function (response) {
                if (response.success) {
                    alert(response.data.message);
                    $('#tip-modal-overlay').fadeOut();
                } else {
                    alert('エラー: ' + response.data.message);
                }
            },
            error: function () {
                alert('通信エラーが発生しました。');
            },
            complete: function() {
                $('#tip-processing-overlay').hide();
                $('#tip-submit-button').prop('disabled', false);
                cardElement.clear(); // フォームをクリア
            }
        });
    }
});

上記のphp、Javascript、CSSの配置でPAY.JPの実装部分は完了です。

最後のStep3で、実際に投げ銭機能を設置したい記事ページにショートコードを配置してみました。

ショートコード:複雑なコードを簡単な短いコード(例: [shortcode])に置き換えて、特定ページにモジュールや定型文を簡単に挿入できる仕組み

image.png

なんと!エラー等起きずに「応援する」ボタンが表示されて、投げ銭機能が実装できました。

image.png

PAY.JPのドキュメントに書かれているテスト用のクレジットカード番号を入力して決済してみたところ、決済成功しました。

PAY.JPの管理画面を確認したところ、設置したページで決済が完了している履歴が記録されていました。

Snipaste_2025-12-18_01-26-23.png

投げ銭機能をもろもろ実装するのに30分ほどしかかかっていません。PAY.JPは生成AIも学習しているようで、しっかり動作する高いコードが生成されました。

※今回実装したコードは動作を優先しており、セキュリティ面の確認まで行っていません。本番で稼働させる場合は、セキュリティ上の脆弱性がないか監査した上で本番リリースしましょう。

金額に応じた感謝のアニメーション効果

せっかくなので、もう少し投げ銭機能に追加機能を実装してみたいと思います。

ライブアプリなどでは投げ銭による支援金額に応じて色々なアニメーションが表示されます。

そこで、支援金額に応じて決済完了時に感謝の気持ちを表すアニメーションが流れるように実装してみました。

  1. 少額(〜499円)
  2. 中額(500円〜2999円)
  3. 高額(3000円〜)

生成AIに指示したところ、以下のようにfunctions.phpの追加修正コードと、payjp-tipping.jsの修正コードが出力されました。

■functions.php

        // Confettiライブラリを追加 (CDNから読み込み)
        wp_enqueue_script('canvas-confetti', 'https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js', array(), null, true);

        // 自作のJSファイル
        wp_enqueue_script(
            'payjp-tipping-js',
            get_stylesheet_directory_uri() . '/payjp-tipping.js',
            array('jquery', 'payjp-js', 'canvas-confetti'), // 変更後の箇所: canvas-confettiに依存
            filemtime(get_stylesheet_directory() . '/payjp-tipping.js'),
            true
        );

■payjp-tipping.js

jQuery(function ($) {
    // --- 初期設定 ---
    // 必要な要素やライブラリが存在しない場合は処理を中断
    if (typeof Payjp === 'undefined' || $('#show-tip-modal').length === 0 || typeof confetti === 'undefined') {
        return;
    }
    const payjp = Payjp(payjp_tipping_vars.public_key);
    const elements = payjp.elements();
    const cardElement = elements.create('card');
    cardElement.mount('#card-element');

    // --- モーダルの表示・非表示イベント ---
    $('#show-tip-modal').on('click', function () {
        $('#tip-modal-overlay').fadeIn();
    });
    $('#close-tip-modal, #tip-modal-overlay').on('click', function (e) {
        if (e.target.id === 'close-tip-modal' || e.target.id === 'tip-modal-overlay') {
            $('#tip-modal-overlay').fadeOut();
        }
    });
    $('#tip-modal').on('click', function (e) {
        e.stopPropagation();
    });
    $('input[name="tip_amount"]').on('change', function() {
        if ($(this).val() === 'custom') {
            $('#custom-amount-input').show().focus();
        } else {
            $('#custom-amount-input').hide();
        }
    });
    
    /**
     * ★新機能★ 決済完了アニメーションを実行する関数
     * @param {number} amount - 投げ銭の金額
     * @param {string} message - 完了メッセージ
     */
    function showTippingAnimation(amount, message) {
        // z-indexをモーダルより上(1001)に設定
        const confettiOptions = { zIndex: 1001 };

        // 金額に応じてアニメーションを分岐
        if (amount >= 3000) {
            // 高額: 豪華な花火風アニメーション
            const duration = 3 * 1000;
            const animationEnd = Date.now() + duration;
            const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 1001 };

            function randomInRange(min, max) {
                return Math.random() * (max - min) + min;
            }
            const interval = setInterval(function() {
                const timeLeft = animationEnd - Date.now();
                if (timeLeft <= 0) { return clearInterval(interval); }
                const particleCount = 50 * (timeLeft / duration);
                confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 } }));
                confetti(Object.assign({}, defaults, { particleCount, origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 } }));
            }, 250);
        } else if (amount >= 500) {
            // 中額: 画面中央からたくさん
            confetti({ ...confettiOptions, particleCount: 150, spread: 100, origin: { y: 0.6 } });
        } else {
            // 少額: ささやかな紙吹雪
            confetti({ ...confettiOptions, particleCount: 70, spread: 70, origin: { y: 0.8 } });
        }
        
        // アニメーションが終わるのを待ってからメッセージ表示とモーダルを閉じる
        const closeDelay = (amount >= 3000) ? 3000 : 1500;
        setTimeout(function() {
            alert(message);
            $('#tip-modal-overlay').fadeOut();
            // フォームの状態をリセット
            $('#tip-submit-button').prop('disabled', false);
            cardElement.clear();
        }, closeDelay);
    }
    
    /**
     * ★改善版★ トークンをサーバーに送信する関数
     * @param {string} token - PAY.JPから受け取ったトークン
     */
    function sendTokenToServer(token) {
        let amount = $('input[name="tip_amount"]:checked').val();
        if (amount === 'custom') {
            amount = $('#custom-amount-input').val();
        }
        const numericAmount = parseInt(amount, 10);

        $.ajax({
            type: 'POST',
            url: payjp_tipping_vars.ajax_url,
            data: {
                action: 'process_tip_payment',
                nonce: payjp_tipping_vars.nonce,
                token: token,
                amount: numericAmount,
                post_id: $('body').hasClass('single') ? $('article').attr('id').replace('post-', '') : 0
            },
            dataType: 'json',
            success: function (response) {
                $('#tip-processing-overlay').hide();
                if (response.success) {
                    // 成功!アニメーション関数を呼び出す
                    showTippingAnimation(numericAmount, response.data.message);
                } else {
                    // サーバー側での決済エラー
                    $('#card-errors').text(response.data.message);
                    $('#tip-submit-button').prop('disabled', false);
                }
            },
            error: function () {
                // 通信エラー
                $('#tip-processing-overlay').hide();
                $('#card-errors').text('通信エラーが発生しました。時間をおいて再度お試しください。');
                $('#tip-submit-button').prop('disabled', false);
            }
        });
    }
    
    // --- フォーム送信処理 ---
    $('#payjp-tip-form').on('submit', function (e) {
        e.preventDefault();
        
        // 既存のエラーメッセージをクリア
        $('#card-errors').text(''); 
        
        $('#tip-processing-overlay').show();
        $('#tip-submit-button').prop('disabled', true);

        payjp.createToken(cardElement).then(function (response) {
            if (response.error) {
                $('#card-errors').text(response.error.message);
                $('#tip-processing-overlay').hide();
                $('#tip-submit-button').prop('disabled', false);
            } else {
                sendTokenToServer(response.id);
            }
        });
    });
});

functions.phpとpayjp-tipping.jsを修正によって、

より支援金額が上がるにつれて豪華なアニメーションが流れるようになっています。

◯投げ銭100円の場合

◯投げ銭3000円の場合

3000円以上の投げ銭をすると、大量の紙吹雪が舞うようになっています。

高額のチップを支援してくれたユーザーに感謝をアニメーションで伝えることができるようになりました。

通常のプラグイン機能による実装だと、サポート上難しいですが、AIコーディングによって実装しているため、思いついた機能もすぐに実装できました。

あくまでテスト用のAPIキーで、本番運用ではありませんが、しっかりコードチェックして脆弱性がなければ、実際にPAY.JPによるワードプレスの投げ銭機能が導入可能です。

生成AIで簡単にPAY.JPの実装が可能に

生成AIによってPAY.JPのワードプレスへの実装は非常に身近なものになりました。

決済関連のサービスは導入難易度があり、非エンジニアではなかなか難しかったです。

しかし、生成AIの発展によってAIコーディングでPAY.JPを実装できるようになりました。

投げ銭プラグインでは難しいアニメーションの導入や細かな部分の調整も可能です。

PAY.JPは日本の企業で、オンラインECプラットフォームを展開するBASEで培った決済技術を展開しています。

海外企業の場合、サポートの部分やドキュメントで不安な点も多いですが、サポートも安心で公式ドキュメントも読みやすいです。

非エンジニアでも自分のサイトに決済機能を手軽に実装できる時代がついにやって来たのだなと痛感しました。

終わりに

今回、自身が運営しているワードプレスに投げ銭機能をPAY.JPを使って実装してみました。

PAY.JPはドキュメントが充実しており、利用事例もあるため、生成AIによるAIコーディングでさくっと2時間ほどで実装できました。

ワードプレスのプラグインなどで投げ銭サービスが提供されているものもありますが、PAY.JPの方が決済手数料も安いです。

かつては決済の実装は難易度の高い実装でしたが、こうした決済サービスの登場と生成AIによって非エンジニアでもAIとやり取りして実装できるようになってきました。

ぜひ自分のワードプレスでも投げ銭機能を搭載してみたい、感謝のアニメーションなどの工夫もしてみたい方は、今回の記事を参考に実装してみてください。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?