Files
stripe-checkout/stripe-checkout-simple.php
2026-02-03 11:15:43 +02:00

305 lines
11 KiB
PHP

<?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');