題名が長くなりましたが、以下のプラグインを自分のサービスで利用するために開発しました。
プラグイン自体は可能な限りシンプルにしていて、以下の機能に絞っています。
- 購入されたライセンスキーを暗号化して Rest API で出力
- 商品にライセンスキーを付与するかのチェック
- ライセンスキーの有効期日の指定
後は、購入したユーザーが、Web サービス上でメールで届いたライセンスキーを入力すると、それを復号化して検証するという仕組みです。それについては、Web サービス上でコードを書く必要があります。暗号化は、OpenSSL の共通パスフレーズを用いています。コードに関しては、WordPress の管理画面上での PHP と、React で以下に記していきますが、Rest API と、OpenSSL を利用しているので、他の言語やシステムでも別のコードを書けば使えると思います。その辺りに詳しい方は、チャレンジしてみてください。
動作
ライセンスキー販売サイトの商品の設定
ライセンスキーを発行にチェックし、有効期限を決めます。有効期限を過ぎると、REST API への暗号化されたライセンスキーの出力は無くなります。商品は、バーチャルにチェックを入れます。
ライセンスキー販売サイトのプラグイン側の設定
共通パスフレーズを決めます。これは流出しないように大切に保管してください。また、プラグインの設定画面上で、REST API の URL を知る事ができます。この2点は、後で PHP と React 上に書き込みます。
Web サービス側の PHP コード
子テーマの、functions.php に書く前提で記していきます。
ライセンスキーを入力するためのメニューページを作成するコード
- 管理画面に、Test License というページを作成
- ページには、React を利用するので、id 属性を指定して、echo するのみ
/** ==================================================
* Add Menu for Test license
*
* @since 1.00
*/
function add_pages() {
add_menu_page(
'Test License',
'Test License',
'edit_posts',
'TestLicense',
'credit_page'
);
}
add_action( 'admin_menu', 'add_pages' );
/** ==================================================
* Credit
*
* @since 1.00
*/
function credit_page() {
echo '<div id="test-license-page"></div>';
}
メニューページに読み込むスクリプト用のコード
- 子テーマ内に、test-license というフォルダを作成し、その下の dist フォルダ内に、React の build ファイルを置くためのコード
/** ==================================================
* License Page Scripts
*
* @param string $hook_suffix hook_suffix.
* @since 1.00
*/
function license_page_scripts( $hook_suffix ) {
if ( 'toplevel_page_TestLicense' !== $hook_suffix ) {
return;
}
$asset_file = include( get_stylesheet_directory() . '/test-license/dist/test-license.asset.php' );
wp_enqueue_style(
'test-license-style',
get_stylesheet_directory_uri() . '/test-license/dist/test-license.css',
array( 'wp-components' ),
'1.0.0'
);
wp_enqueue_script(
'test-license',
get_stylesheet_directory_uri() . '/test-license/dist/test-license.js',
$asset_file['dependencies'],
$asset_file['version'],
true
);
}
add_action( 'admin_enqueue_scripts', 'license_page_scripts', 10, 1 );
REST API を出力し、入力されたライセンスキーを検証するコード
- 権限は以下の場合は編集者権限
- license_api_verify 内の検証コード内に、復号化のための共通パスフレーズを記す
- 検証して、入力されたライセンスキーと、プラグインの入っているライセンスキー販売サイトの REST API を復号化したものが一致していれば、ユーザーオプションテーブルの test_licensed を true にする
/** ==================================================
* Register Rest API
*
* @since 1.00
*/
function register_rest() {
register_rest_route(
'test/license_api',
'/token',
array(
'methods' => 'POST',
'callback' => 'license_api_verify',
'permission_callback' => 'editor_rest_permission',
)
);
}
add_action( 'rest_api_init', 'register_rest' );
/** ==================================================
* Rest Permission for editor
*
* @since 1.00
*/
function editor_rest_permission() {
return current_user_can( 'edit_posts' );
}
/** ==================================================
* License Rest API verify
*
* @param object $request changed data.
* @since 1.00
*/
function license_api_verify( $request ) {
$args = json_decode( $request->get_body(), true );
$input_license_key = $args['license_key'];
$get_license_api_arr = $args['license_api'];
foreach ( $get_license_api_arr as $key => $value ) {
/* 共通パスフレーズは、プラグイン側で指定したもの。以下の場合は、'm#xs@%5NhZlR' */
$get_license_key = openssl_decrypt( $value['open_key'], 'aes-256-cfb', 'm#xs@%5NhZlR', 0, openssl_cipher_iv_length( 'aes-256-cfb' ) );
if ( $get_license_key === $input_license_key ) {
/* ライセンスが一致した時の処理 */
update_user_option( get_current_user_id(), 'test_licensed', true );
}
}
$args['licensed'] = get_user_option( 'test_licensed', get_current_user_id() );
return new WP_REST_Response( $args, 200 );
}
Web サービス側の React コード
LicenseCheck コンポーネント
- Fetch で販売サイトの REST API を取得
- apiFetch で Web サービス側で、ライセンスキーを入力したものと、Fetch で取得した暗号化されたライセンスキーを php 側と通信
import './license-check.css';
import apiFetch from '@wordpress/api-fetch';
import { Button, TextControl } from '@wordpress/components';
import {
useState,
useEffect
} from '@wordpress/element';
const LicenseCheck = ( props ) => {
const [ paidFlag, updatePaidFlag ] = useState( false );
const [ paidText, updatePaidText ] = useState( '' );
const [ currentLicense, updateCurrentLicense ] = useState( '' );
const [ licenseApi, updateLicenseApi ] = useState( {} );
const items_licensed = [];
if ( ! paidFlag ) {
items_licensed.push(
<div>
<hr />
<h3>{ props.license_text }</h3>
<p className="description">{ props.purchase_description }</p>
<div>
<Button
className="button button-large"
href={ props.purchase_site }
target="_blank"
>
{ props.purchase_text }
</Button>
</div>
<div className="license_key_input_line">
{ props.license_text_input }
<TextControl
className = "license_key_input"
value = { currentLicense }
onChange = { ( value ) => updateCurrentLicense( value ) }
/>
</div>
</div>
);
}
useEffect( () => {
fetch( props.url )
.then( response => response.json() )
.then( data => {
//console.log( data );
updateLicenseApi( data );
} );
apiFetch( {
path: props.path,
method: 'POST',
data: {
license_key: currentLicense,
license_api: licenseApi,
}
} ).then( ( response ) => {
//console.log( response );
if ( response['licensed'] ) {
updatePaidFlag( true );
updatePaidText( props.paid_text );
} else {
updatePaidFlag( false );
updatePaidText( props.no_paid_text );
}
} );
}, [ currentLicense ] );
return (
<div className="wrap">
<h2>{ props.title }</h2>
<h3>{ paidText }</h3>
{ items_licensed }
</div>
);
};
export default LicenseCheck;
コンポーネント用の CSS
.license_key_input {
width: 200px;
}
.license_key_input_line {
display: inline-flex;
}
メインのコード
- コンポーネントを読み込む。コンポーネントの属性に各種値を入力。
- 属性
- title : タイトル
- license_text : タイトル2
- purchase_description : 購入の説明
- purchase_text : 購入ボタンの文字
- purchase_site : ライセンスキー商品販売ページの URL
- license_text_input : ライセンスキー入力フォームの左側のテキスト
- paid_text : ライセンスされている事を示すテキスト
- no_paid_text : ライセンスされていない事を示すテキスト
- url : ライセンス販売サイトの REST API の URL(プラグインの設定画面に記してあるもの)
- path : Web サービス側の REST API のパス(PHP に記したパス)
import './test-license.scss';
import { render } from '@wordpress/element';
import LicenseCheck from './components/license-check';
const TestLicenseView = () => {
return (
<div className="wrap">
<LicenseCheck
title = { 'ライセンスチェックテスト' }
license_text = { 'ライセンスキー' }
purchase_description = { '以下のショップで購入したライセンスキーを入力すると制限が解除されます。' }
purchase_site = 'https://shop-jp.riverforest.test/product/license'
purchase_text = { '購入' }
license_text_input = { 'ライセンスキー入力' }
paid_text = { 'ライセンス済み' }
no_paid_text = { '未ライセンス' }
/* REST API by Simple License Key for WooCommerce */
url = 'https://shop-jp.riverforest.test/wp-json/rf/slk-woo-open-key_api/token'
/* Web service REST API */
path = 'test/license_api/token'
/>
</div>
);
};
render(
<TestLicenseView />,
document.getElementById( 'test-license-page' )
);
メインの CSS
#test-license-page {
}
ダウンロード
コードを子テーマ毎一式以下に置きました。
コメントを残す