commit e61027f22fd27d34db4e41e8063ecd01333ecfbd
parent 5c1251397d1fc160326885fc17cd72f592d945ba
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 3 Nov 2025 17:51:09 +0100
sanitization
Diffstat:
9 files changed, 51 insertions(+), 34 deletions(-)
diff --git a/README.md b/README.md
@@ -1,5 +1,11 @@
-# GNU Taler Turnstile for WordPress
-
+# GNU Taler Turnstile
+Contributors: grothoff
+Tags: payment, monetization, privacy, subscription
+Requires at least: 6.3
+Tested up to: 6.8
+Stable tag: 1.1.0
+Requires PHP: 8.0
+License: GPLv2 or later
A WordPress plugin that adds price fields to posts and requires
payment via GNU Taler for access.
@@ -175,7 +181,7 @@ For issues and questions:
## License
-This plugin is licensed under GNU GPL v3 or later.
+This plugin is licensed under GNU GPL v2 or later.
## Credits
diff --git a/admin/class-admin-settings.php b/admin/class-admin-settings.php
@@ -163,6 +163,7 @@ class Taler_Turnstile_Admin_Settings {
'taler_turnstile_enabled_post_types',
'fields_added',
sprintf(
+ /* translators: placeholder is category type to which fields were added */
__('Price category fields added to: %s', 'taler-turnstile'),
implode(', ', $type_labels)
),
@@ -189,6 +190,7 @@ class Taler_Turnstile_Admin_Settings {
'taler_turnstile_enabled_post_types',
'fields_removed',
sprintf(
+ /* translators: placeholder is category type to which fields were removed */
__('Price category fields removed from: %s', 'taler-turnstile'),
implode(', ', $type_labels)
),
@@ -285,6 +287,7 @@ class Taler_Turnstile_Admin_Settings {
add_settings_error(
'taler_turnstile_settings',
'backend_error',
+ /* translators: placeholder is the numeric HTTP status code */
sprintf(__('Unexpected response (%d) from merchant backend', 'taler-turnstile'), $http_status),
'error'
);
@@ -324,7 +327,8 @@ class Taler_Turnstile_Admin_Settings {
<p>
<?php
printf(
- esc_html__('Backend configured successfully! You can now %sconfigure subscription prices%s.', 'taler-turnstile'),
+ /* translators: placeholders are the HTML to generate a link (beginning and end) to the configuration page */
+ esc_html__('Backend configured successfully! You can now %1$sconfigure subscription prices%2$s.', 'taler-turnstile'),
'<a href="' . esc_url(admin_url('admin.php?page=taler-subscription-prices')) . '">',
'</a>'
);
diff --git a/admin/class-price-category-admin.php b/admin/class-price-category-admin.php
@@ -172,15 +172,19 @@ class Taler_Turnstile_Price_Category_Admin {
public function save_price_category() {
if (!current_user_can('manage_options')) {
- wp_die(__('You do not have sufficient permissions to access this page.', 'taler-turnstile'));
+ wp_die(esc_html(__('You do not have sufficient permissions to access this page.', 'taler-turnstile')));
}
check_admin_referer('taler_save_price_category');
$subscriptions = Taler_Merchant_API::get_subscriptions();
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
$label = isset($_POST['label']) ? sanitize_text_field($_POST['label']) : '';
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
$description = isset($_POST['description']) ? sanitize_textarea_field($_POST['description']) : '';
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$prices = isset($_POST['prices']) ? $_POST['prices'] : array();
// Determine if this is an edit or new category
diff --git a/admin/class-subscription-prices-admin.php b/admin/class-subscription-prices-admin.php
@@ -71,7 +71,8 @@ class Taler_Subscription_Prices_Admin {
<p>
<?php
printf(
- esc_html__('Turnstile payment backend is not configured. Please %sconfigure the backend%s first.', 'taler-turnstile'),
+ /* translators: placeholders are the HTML to generate the link (beginning and end) */
+ esc_html__('Turnstile payment backend is not configured. Please %1$sconfigure the backend%1$s first.', 'taler-turnstile'),
'<a href="' . esc_url(admin_url('options-general.php?page=taler-turnstile-settings')) . '">',
'</a>'
);
@@ -167,6 +168,7 @@ class Taler_Subscription_Prices_Admin {
<p class="description">
<?php
printf(
+ /* translators: placeholder is the currency code (like "USD" or "EUR") */
esc_html__('Leave empty to prevent buying this subscription with %s.', 'taler-turnstile'),
esc_html($currency_code)
);
@@ -196,6 +198,8 @@ class Taler_Subscription_Prices_Admin {
check_admin_referer('taler_save_subscription_prices');
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$subscription_prices = isset($_POST['subscription_prices']) ? $_POST['subscription_prices'] : array();
// Validate and sanitize
diff --git a/includes/class-content-filter.php b/includes/class-content-filter.php
@@ -83,14 +83,14 @@ class Taler_Content_Filter {
$full_subscriptions = Taler_Price_Category::get_full_subscriptions($price_category['prices']);
foreach ($full_subscriptions as $subscription_id) {
if (self::is_subscriber($subscription_id)) {
- debug_log('Subscriber access granted');
+ self::debug_log('Subscriber access granted');
return $content;
}
}
// Check if this session already has access
if (self::has_session_access($post->ID)) {
- debug_log('Session access already granted');
+ self::debug_log('Session access already granted');
return $content;
}
@@ -100,11 +100,11 @@ class Taler_Content_Filter {
$order_status = Taler_Merchant_API::check_order_status($order_info['order_id']);
if ($order_status && $order_status['paid']) {
- info_log('Taler Turnstile: Order was paid, granting session access');
+ self::debug_log('Taler Turnstile: Order was paid, granting session access');
self::grant_session_access($post->ID);
if (!empty($order_status['subscription_slug'])) {
- info_log('Taler Turnstile: Subscription was purchased, granting subscription access');
+ self::debug_log('Taler Turnstile: Subscription was purchased, granting subscription access');
self::grant_subscriber_access(
$order_status['subscription_slug'],
$order_status['subscription_expiration']
@@ -129,7 +129,7 @@ class Taler_Content_Filter {
// Need to create a new order if we don't have a valid one
if (!$order_info) {
- info_log('Creating new order for ' . $post->ID);
+ self::debug_log('Creating new order for ' . $post->ID);
$order_info = Taler_Merchant_API::create_order($post->ID);
}
@@ -148,7 +148,7 @@ class Taler_Content_Filter {
// Store order info in session
self::store_order_node_mapping($post->ID, $order_info);
- info_log('Showing paywall page for ' . $post->ID);
+ self::debug_log('Showing paywall page for ' . $post->ID);
// User needs to pay - show teaser + payment button
return self::render_paywall($post, $order_info);
}
@@ -222,6 +222,7 @@ class Taler_Content_Filter {
<!-- div class="taler-payment-info">
<p class="taler-order-id">
+ /* translators: placeholder is the order ID of the merchant backend */
<small><?php printf(esc_html__('Order ID: %s', 'taler-turnstile'), esc_html($order_id)); ?></small>
</p>
</div -->
@@ -275,11 +276,7 @@ class Taler_Content_Filter {
session_start();
}
- if (!isset($_SESSION['taler_turnstile_subscriptions'][$subscription_slug])) {
- return false;
- }
-
- $expiration = $_SESSION['taler_turnstile_subscriptions'][$subscription_slug];
+ $expiration = $_SESSION['taler_turnstile_subscriptions'][$subscription_slug] ?? 0;
return $expiration >= time();
}
@@ -344,10 +341,15 @@ class Taler_Content_Filter {
session_start();
}
- if (!isset($_SESSION['taler_turnstile_node_orders'][$post_id])) {
- return null;
- }
+ return $_SESSION['taler_turnstile_node_orders'][$post_id] ?? NULL;
+ }
- return $_SESSION['taler_turnstile_node_orders'][$post_id];
+ /**
+ * Helper function for logging that is easily turned off.
+ *
+ * @param string $msg The log message
+ */
+ private static function debug_log($msg) {
+ // error_log($msg);
}
}
\ No newline at end of file
diff --git a/includes/class-field-manager.php b/includes/class-field-manager.php
@@ -99,6 +99,8 @@ class Taler_Field_Manager {
*/
public static function save_price_category_meta($post_id, $post) {
// Check nonce
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
if (!isset($_POST['taler_price_category_nonce']) ||
!wp_verify_nonce($_POST['taler_price_category_nonce'], 'taler_price_category_meta')) {
return;
diff --git a/includes/class-price-category.php b/includes/class-price-category.php
@@ -99,6 +99,7 @@ class Taler_Price_Category {
);
$description = sprintf(
+ /* translators: placeholder is the currency code (like "USD" or "EUR") */
__('Pay in %s with subscription', 'taler-turnstile'),
$currency_code
);
@@ -122,6 +123,7 @@ class Taler_Price_Category {
);
$description = sprintf(
+ /* translators: placeholder is the currency code (like "USD" or "EUR") */
__('Buy subscription in %s', 'taler-turnstile'),
$currency_code
);
@@ -137,6 +139,7 @@ class Taler_Price_Category {
} else {
// No subscription case
$description = sprintf(
+ /* translators: placeholder is the currency code (like "USD" or "EUR") */
__('Pay in %s', 'taler-turnstile'),
$currency_code
);
diff --git a/includes/class-taler-merchant-api.php b/includes/class-taler-merchant-api.php
@@ -45,7 +45,7 @@ class Taler_Merchant_API {
return null;
}
- $parsed_url = parse_url($backend_url);
+ $parsed_url = wp_parse_url($backend_url);
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '/';
$cleaned_path = preg_replace('#^/instances/[^/]+/?#', '/', $path);
diff --git a/taler-turnstile.php b/taler-turnstile.php
@@ -1,14 +1,13 @@
<?php
/**
* Plugin Name: GNU Taler Turnstile
- * Plugin URI: https://taler.net
+ * Plugin URI: https://git.taler.net/wordpress-turnstile.git
* Description: Adds price fields to posts and requires payment for access via GNU Taler.
- * Version: 0.9.0
+ * Version: 1.1.0
* Author: GNU Taler
- * Author URI: https://taler.net
- * License: GPL v3 or later
+ * Author URI: https://grothoff.org/christian/
+ * License: GPL v2 or later
* Text Domain: taler-turnstile
- * Domain Path: /languages
*/
// Exit if accessed directly
@@ -57,15 +56,8 @@ class Taler_Turnstile {
}
public function init() {
- load_plugin_textdomain('taler-turnstile', false, dirname(plugin_basename(__FILE__)) . '/languages');
-
- // Initialize field manager
Taler_Field_Manager::init();
-
- // Initialize content filter
Taler_Content_Filter::init();
-
- // Initialize admin classes
if (is_admin()) {
new Taler_Turnstile_Admin_Settings();
new Taler_Turnstile_Price_Category_Admin();