first commit
This commit is contained in:
69
assets/scs-checkout.js
Normal file
69
assets/scs-checkout.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
(function () {
|
||||||
|
function parsePayload(element) {
|
||||||
|
var raw = element.getAttribute('data-scs') || '{}';
|
||||||
|
try {
|
||||||
|
return JSON.parse(raw);
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBusy(button, busy) {
|
||||||
|
button.disabled = !!busy;
|
||||||
|
button.setAttribute('data-loading', busy ? '1' : '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', function (event) {
|
||||||
|
var button = event.target.closest('.scs-checkout-button');
|
||||||
|
if (!button) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
if (button.getAttribute('data-loading') === '1') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload = parsePayload(button);
|
||||||
|
if (!payload || !payload.nonce) {
|
||||||
|
alert((window.scs_ajax && scs_ajax.error_text) || 'Unable to start payment.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBusy(button, true);
|
||||||
|
|
||||||
|
var formData = new FormData();
|
||||||
|
formData.append('action', 'scs_create_session');
|
||||||
|
formData.append('nonce', payload.nonce);
|
||||||
|
formData.append('payload', JSON.stringify(payload));
|
||||||
|
|
||||||
|
var ajaxUrl = (window.scs_ajax && scs_ajax.ajax_url) || '';
|
||||||
|
|
||||||
|
fetch(ajaxUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(function (data) {
|
||||||
|
if (data && data.success && data.data && data.data.url) {
|
||||||
|
window.location.href = data.data.url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = (data && data.data && data.data.message)
|
||||||
|
? data.data.message
|
||||||
|
: ((window.scs_ajax && scs_ajax.error_text) || 'Unable to start payment.');
|
||||||
|
|
||||||
|
alert(message);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
alert((window.scs_ajax && scs_ajax.error_text) || 'Unable to start payment.');
|
||||||
|
})
|
||||||
|
.finally(function () {
|
||||||
|
setBusy(button, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
304
stripe-checkout-simple.php
Normal file
304
stripe-checkout-simple.php
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
Plugin Name: Stripe Checkout Simple
|
||||||
|
Description: Add a shortcode to create a Stripe Checkout Session and redirect to the hosted Checkout page.
|
||||||
|
Version: 0.1.0
|
||||||
|
Author: MrAkells
|
||||||
|
Author URI: https://t.me/mrakells
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('ABSPATH')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
define('SCS_VERSION', '0.1.0');
|
||||||
|
define('SCS_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||||
|
define('SCS_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||||
|
|
||||||
|
function scs_get_settings() {
|
||||||
|
$defaults = array(
|
||||||
|
'secret_key' => '',
|
||||||
|
'success_url' => '',
|
||||||
|
'cancel_url' => '',
|
||||||
|
'currency' => 'usd',
|
||||||
|
'product_name' => 'Order',
|
||||||
|
'amount' => '',
|
||||||
|
);
|
||||||
|
|
||||||
|
$settings = get_option('scs_settings', array());
|
||||||
|
if (!is_array($settings)) {
|
||||||
|
$settings = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return wp_parse_args($settings, $defaults);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_register_settings() {
|
||||||
|
register_setting('scs_settings_group', 'scs_settings', 'scs_sanitize_settings');
|
||||||
|
|
||||||
|
add_settings_section(
|
||||||
|
'scs_main',
|
||||||
|
'Stripe Checkout',
|
||||||
|
'__return_false',
|
||||||
|
'scs_settings'
|
||||||
|
);
|
||||||
|
|
||||||
|
add_settings_field('scs_secret_key', 'Secret key', 'scs_field_secret_key', 'scs_settings', 'scs_main');
|
||||||
|
add_settings_field('scs_success_url', 'Success URL', 'scs_field_success_url', 'scs_settings', 'scs_main');
|
||||||
|
add_settings_field('scs_cancel_url', 'Cancel URL', 'scs_field_cancel_url', 'scs_settings', 'scs_main');
|
||||||
|
add_settings_field('scs_product_name', 'Product name', 'scs_field_product_name', 'scs_settings', 'scs_main');
|
||||||
|
add_settings_field('scs_amount', 'Price (USD)', 'scs_field_amount', 'scs_settings', 'scs_main');
|
||||||
|
}
|
||||||
|
add_action('admin_init', 'scs_register_settings');
|
||||||
|
|
||||||
|
function scs_sanitize_settings($input) {
|
||||||
|
$output = array();
|
||||||
|
$output['secret_key'] = isset($input['secret_key']) ? sanitize_text_field($input['secret_key']) : '';
|
||||||
|
$output['success_url'] = isset($input['success_url']) ? sanitize_text_field($input['success_url']) : '';
|
||||||
|
$output['cancel_url'] = isset($input['cancel_url']) ? sanitize_text_field($input['cancel_url']) : '';
|
||||||
|
$output['currency'] = 'usd';
|
||||||
|
$output['product_name'] = isset($input['product_name']) ? sanitize_text_field($input['product_name']) : '';
|
||||||
|
$output['amount'] = isset($input['amount']) ? sanitize_text_field($input['amount']) : '';
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_field_secret_key() {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$value = esc_attr($settings['secret_key']);
|
||||||
|
echo '<input type="password" name="scs_settings[secret_key]" value="' . $value . '" class="regular-text" autocomplete="off" />';
|
||||||
|
echo '<p class="description">Use your Stripe secret key (sk_test_... or sk_live_...).</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_field_success_url() {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$value = esc_attr($settings['success_url']);
|
||||||
|
echo '<input type="text" name="scs_settings[success_url]" value="' . $value . '" class="regular-text" />';
|
||||||
|
echo '<p class="description">Required. You can include {CHECKOUT_SESSION_ID} in the URL.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_field_cancel_url() {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$value = esc_attr($settings['cancel_url']);
|
||||||
|
echo '<input type="text" name="scs_settings[cancel_url]" value="' . $value . '" class="regular-text" />';
|
||||||
|
echo '<p class="description">Required.</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_field_product_name() {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$value = esc_attr($settings['product_name']);
|
||||||
|
echo '<input type="text" name="scs_settings[product_name]" value="' . $value . '" class="regular-text" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_field_amount() {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$value = esc_attr($settings['amount']);
|
||||||
|
echo '<input type="text" name="scs_settings[amount]" value="' . $value . '" class="regular-text" />';
|
||||||
|
echo '<p class="description">Enter the price in USD (e.g., 59.00).</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_add_admin_menu() {
|
||||||
|
add_options_page('Stripe Checkout', 'Stripe Checkout', 'manage_options', 'scs_settings', 'scs_render_settings_page');
|
||||||
|
}
|
||||||
|
add_action('admin_menu', 'scs_add_admin_menu');
|
||||||
|
|
||||||
|
function scs_render_settings_page() {
|
||||||
|
echo '<div class="wrap">';
|
||||||
|
echo '<h1>Stripe Checkout</h1>';
|
||||||
|
echo '<p>Use the shortcode <code>[stripe_checkout]</code> or pass attributes like <code>button_text</code> and <code>button_class</code>.</p>';
|
||||||
|
echo '<p>Example:</p>';
|
||||||
|
echo '<p><code>[stripe_checkout button_text="Pay now" button_class="btn btn-main"]</code></p>';
|
||||||
|
echo '<form method="post" action="options.php">';
|
||||||
|
settings_fields('scs_settings_group');
|
||||||
|
do_settings_sections('scs_settings');
|
||||||
|
submit_button();
|
||||||
|
echo '</form>';
|
||||||
|
echo '<p style="margin-top: 24px; font-size: 13px; color: #646970;">Author: <a href="https://t.me/mrakells" target="_blank" rel="noopener noreferrer">MrAkells</a></p>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_enqueue_assets() {
|
||||||
|
wp_register_script(
|
||||||
|
'scs-checkout',
|
||||||
|
SCS_PLUGIN_URL . 'assets/scs-checkout.js',
|
||||||
|
array(),
|
||||||
|
SCS_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_localize_script('scs-checkout', 'scs_ajax', array(
|
||||||
|
'ajax_url' => admin_url('admin-ajax.php'),
|
||||||
|
'error_text' => __('Unable to start payment. Please try again.', 'scs'),
|
||||||
|
));
|
||||||
|
|
||||||
|
wp_enqueue_script('scs-checkout');
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_checkout_shortcode($atts) {
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
|
||||||
|
if (empty($settings['secret_key'])) {
|
||||||
|
if (current_user_can('manage_options')) {
|
||||||
|
return '<div class="scs-error">Stripe secret key is not configured.</div>';
|
||||||
|
}
|
||||||
|
return '<div class="scs-error">Payment is unavailable.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$atts = shortcode_atts(array(
|
||||||
|
'button_text' => 'Pay',
|
||||||
|
'button_class' => '',
|
||||||
|
'customer_email' => '',
|
||||||
|
'client_reference_id' => '',
|
||||||
|
), $atts, 'stripe_checkout');
|
||||||
|
|
||||||
|
$payload = array(
|
||||||
|
'customer_email' => $atts['customer_email'] !== '' ? sanitize_email($atts['customer_email']) : '',
|
||||||
|
'client_reference_id' => $atts['client_reference_id'] !== '' ? sanitize_text_field($atts['client_reference_id']) : '',
|
||||||
|
'nonce' => wp_create_nonce('scs_create_session'),
|
||||||
|
);
|
||||||
|
|
||||||
|
scs_enqueue_assets();
|
||||||
|
|
||||||
|
$button_text = $atts['button_text'] !== '' ? sanitize_text_field($atts['button_text']) : 'Pay';
|
||||||
|
$button_class = 'scs-checkout-button';
|
||||||
|
if ($atts['button_class'] !== '') {
|
||||||
|
$tokens = preg_split('/\s+/', $atts['button_class']);
|
||||||
|
$tokens = array_filter($tokens);
|
||||||
|
$tokens = array_map('sanitize_html_class', $tokens);
|
||||||
|
if (!empty($tokens)) {
|
||||||
|
$button_class .= ' ' . implode(' ', $tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$payload_json = esc_attr(wp_json_encode($payload));
|
||||||
|
|
||||||
|
return '<button type="button" class="' . esc_attr($button_class) . '" data-scs="' . $payload_json . '">' . esc_html($button_text) . '</button>';
|
||||||
|
}
|
||||||
|
add_shortcode('stripe_checkout', 'scs_checkout_shortcode');
|
||||||
|
|
||||||
|
function scs_validate_url($url) {
|
||||||
|
$url = trim((string) $url);
|
||||||
|
if ($url === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$placeholder = '{CHECKOUT_SESSION_ID}';
|
||||||
|
$test_url = str_replace($placeholder, 'TEST_SESSION_ID', $url);
|
||||||
|
$test_url = esc_url_raw($test_url);
|
||||||
|
if ($test_url === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function_exists('wp_http_validate_url')) {
|
||||||
|
return wp_http_validate_url($test_url) ? $url : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter_var($test_url, FILTER_VALIDATE_URL) ? $url : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_to_unit_amount($amount, $currency) {
|
||||||
|
$currency = strtolower((string) $currency);
|
||||||
|
$amount = str_replace(',', '.', trim((string) $amount));
|
||||||
|
if ($amount === '') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$number = floatval($amount);
|
||||||
|
if ($number <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$zero_decimal = array('bif', 'clp', 'djf', 'gnf', 'jpy', 'kmf', 'krw', 'mga', 'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf');
|
||||||
|
$multiplier = in_array($currency, $zero_decimal, true) ? 1 : 100;
|
||||||
|
|
||||||
|
return (int) round($number * $multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scs_ajax_create_session() {
|
||||||
|
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'scs_create_session')) {
|
||||||
|
wp_send_json_error(array('message' => 'Invalid request.'), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw_payload = isset($_POST['payload']) ? wp_unslash($_POST['payload']) : '';
|
||||||
|
$payload = json_decode($raw_payload, true);
|
||||||
|
|
||||||
|
if (!is_array($payload)) {
|
||||||
|
$payload = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = scs_get_settings();
|
||||||
|
$secret_key = $settings['secret_key'];
|
||||||
|
|
||||||
|
if (empty($secret_key)) {
|
||||||
|
wp_send_json_error(array('message' => 'Stripe secret key is not configured.'), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $settings['amount'];
|
||||||
|
$currency = 'usd';
|
||||||
|
$name = $settings['product_name'];
|
||||||
|
|
||||||
|
$success_url = scs_validate_url($settings['success_url']);
|
||||||
|
$cancel_url = scs_validate_url($settings['cancel_url']);
|
||||||
|
|
||||||
|
if ($success_url === '' || $cancel_url === '') {
|
||||||
|
wp_send_json_error(array('message' => 'Success and cancel URLs are required.'), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = array(
|
||||||
|
'mode' => 'payment',
|
||||||
|
'success_url' => $success_url,
|
||||||
|
'cancel_url' => $cancel_url,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($payload['customer_email'])) {
|
||||||
|
$body['customer_email'] = sanitize_email($payload['customer_email']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($payload['client_reference_id'])) {
|
||||||
|
$body['client_reference_id'] = sanitize_text_field($payload['client_reference_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$unit_amount = scs_to_unit_amount($amount, $currency);
|
||||||
|
if ($unit_amount <= 0 || $name === '') {
|
||||||
|
wp_send_json_error(array('message' => 'Provide a valid amount and product name in settings.'), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$body['line_items[0][price_data][currency]'] = $currency;
|
||||||
|
$body['line_items[0][price_data][unit_amount]'] = $unit_amount;
|
||||||
|
$body['line_items[0][price_data][product_data][name]'] = $name;
|
||||||
|
$body['line_items[0][quantity]'] = 1;
|
||||||
|
|
||||||
|
$response = wp_remote_post('https://api.stripe.com/v1/checkout/sessions', array(
|
||||||
|
'headers' => array(
|
||||||
|
'Authorization' => 'Bearer ' . $secret_key,
|
||||||
|
),
|
||||||
|
'body' => $body,
|
||||||
|
'timeout' => 60,
|
||||||
|
));
|
||||||
|
|
||||||
|
if (is_wp_error($response)) {
|
||||||
|
wp_send_json_error(array('message' => $response->get_error_message()), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = wp_remote_retrieve_response_code($response);
|
||||||
|
$response_body = wp_remote_retrieve_body($response);
|
||||||
|
$data = json_decode($response_body, true);
|
||||||
|
|
||||||
|
if ($status < 200 || $status >= 300) {
|
||||||
|
$message = 'Stripe error.';
|
||||||
|
if (is_array($data) && isset($data['error']['message'])) {
|
||||||
|
$message = $data['error']['message'];
|
||||||
|
}
|
||||||
|
wp_send_json_error(array('message' => $message), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($data) || empty($data['url'])) {
|
||||||
|
wp_send_json_error(array('message' => 'Stripe did not return a Checkout URL.'), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success(array('url' => $data['url']));
|
||||||
|
}
|
||||||
|
add_action('wp_ajax_scs_create_session', 'scs_ajax_create_session');
|
||||||
|
add_action('wp_ajax_nopriv_scs_create_session', 'scs_ajax_create_session');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user