commit 33f75c04c03b343655f3b695acdae770fea4ff47
parent 489bb0a98a869961dd9803dd54f52c364ce74e61
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 8 Oct 2025 20:08:36 +0200
content transformation works for articles
Diffstat:
| M | turnstile.module | | | 154 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
1 file changed, 98 insertions(+), 56 deletions(-)
diff --git a/turnstile.module b/turnstile.module
@@ -13,7 +13,6 @@ use GuzzleHttp\Exception\RequestException;
-
/**
* Implements hook_entity_bundle_field_info_alter().
*/
@@ -54,9 +53,11 @@ function turnstile_entity_view_alter(array &$build, EntityInterface $entity, Ent
\Drupal::logger('turnstile')->debug('Not a node, skipping Turnstile checks.');
return;
}
+ /** @var \Drupal\node\NodeInterface $node */
+ $node = $entity;
// Check if the node has a price field and it's not empty.
- if (!$entity->hasField('field_price') || $entity->get('field_price')->isEmpty()) {
+ if (!$node->hasField('field_price') || $node->get('field_price')->isEmpty()) {
\Drupal::logger('turnstile')->debug('Node has no price, skipping Turnstile checks.');
return;
}
@@ -66,73 +67,50 @@ function turnstile_entity_view_alter(array &$build, EntityInterface $entity, Ent
$enabled_types = $config->get('enabled_content_types') ?: [];
// Check if this node type is enabled for paywall.
- if (!in_array($entity->bundle(), $enabled_types)) {
+ if (!in_array($node->bundle(), $enabled_types)) {
+ // NOTE: This case is very strange: how can we have a field_price if
+ // turnstile is not enabled?
\Drupal::logger('turnstile')->debug('Bundle not enabled with Turnstile, skipping payment.');
return;
}
// Get the original body content.
- if (!$entity->hasField('body')) {
+ if (!$node->hasField('body')) {
\Drupal::logger('turnstile')->debug('Note has no body, skipping payment.');
return;
}
- if ($entity->get('body')->isEmpty()) {
+ if ($node->get('body')->isEmpty()) {
\Drupal::logger('turnstile')->debug('Note has empty body, skipping payment.');
return;
}
+ $body_value = $node->get('body')->value;
- $body_value = $entity->get('body')->value;
- // Call the paywall check function with the node.
- \Drupal::logger('turnstile')->debug('Checking for payment...');
- $transformed_body = turnstile_check_paywall_cookie($body_value, $entity);
-
- // Update the body in the build array.
- // FIXME: this somehow does not work, the body is not there!
- if (isset($build['body'][0]['#text'])) {
- \Drupal::logger('turnstile')->debug('Transformed body for Turnstile.');
- $build['body'][0]['#text'] = $transformed_body;
- }
- else
- {
- \Drupal::logger('turnstile')->debug('Failed to inject transformed body.');
- }
-}
-
-
-/**
- * Custom function to check paywall cookie and transform content.
- *
- * @param string $body
- * The original body content.
- * @param \Drupal\node\NodeInterface $node
- * The node entity.
- *
- * @return string
- * The transformed body content.
- */
-function turnstile_check_paywall_cookie($body, NodeInterface $node) {
- // Start session if not already started.
+ // Start session if not already started, we use it to persist payment status data.
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
+ \Drupal::logger('turnstile')->debug('Checking for payment...');
// Check if user is a subscriber.
+ // NOTE: setting subscriber status is not yet supported!
if (isset($_SESSION['turnstile_subscriber']) &&
$_SESSION['turnstile_subscriber'] === TRUE) {
- \Drupal::logger('turnstile')->debug('Subscriber cookie detected, passing turnstile');
// FIXME: should set turnstile_subscriber to *expiration* time
// of the subscription and check not for TRUE but for "greater
// current time".
- // Subscribers have full access to everything
- return $body;
+ // FIXME: For now, subscribers have full access to everything
+ // in the future, we may want to have 50%-off subscriptions
+ // and others where we need to check the exact type of subscription.
+ \Drupal::logger('turnstile')->debug('Subscriber cookie detected, granting access.');
+ return;
}
// Check if there's an existing order for this article.
- $node_id = $node ? $node->id() : NULL;
+ $node_id = $node->id();
if (!$node_id) {
// Strange, but not a case where we can do a payment.
\Drupal::logger('turnstile')->debug('No payment due to lack of node ID...');
- return $body;
+ return;
}
if (isset($_SESSION['turnstile_orders'][$node_id])) {
@@ -141,10 +119,12 @@ function turnstile_check_paywall_cookie($body, NodeInterface $node) {
// Check if order is paid and not refunded.
// FIXME: refunds are not really supported, do we care to
// keep support for them here?
- if (isset($order['paid']) && $order['paid'] === TRUE &&
- (!isset($order['refunded']) || $order['refunded'] === FALSE)) {
+ if (isset($order['paid']) &&
+ (TRUE === $order['paid']) &&
+ ( (! isset($order['refunded'])) ||
+ (FALSE === $order['refunded'])) ) {
\Drupal::logger('turnstile')->debug('Paid order detected, passing Turnstile.');
- return $body;
+ return;
}
// Check order status with backend if not marked as paid.
@@ -157,7 +137,7 @@ function turnstile_check_paywall_cookie($body, NodeInterface $node) {
// for refunds here as well!
\Drupal::logger('turnstile')->debug('Updating order status to paid.');
$_SESSION['turnstile_orders'][$node_id]['paid'] = TRUE;
- return $body;
+ return;
}
}
}
@@ -170,13 +150,78 @@ function turnstile_check_paywall_cookie($body, NodeInterface $node) {
$config = \Drupal::config('turnstile.settings');
$grant_access_on_error = $config->get('grant_access_on_error') ?: true;
if ($grant_access_on_error) {
- return $body;
+ return;
}
- return 'Error: failed to setup order with payment backend';
+ // FIXME: transform body into error message!
+ // 'Error: failed to setup order with payment backend'
+ return;
}
\Drupal::logger('turnstile')->debug('Rendering page with payment request.');
- return turnstile_render_preview_with_payment_button($body, $order_info);
+
+ _turnstile_transform_body_recursive ($build, $node, $order_info);
+
+ // FIXME: we probably need to invalidate caches using
+ // something like this (untested!)
+ // $build['body']['#cache']['contexts'][] = 'user.permissions';
+
+}
+
+
+/**
+ * Recursively traverses a render array to trim full body text to summary
+ * and append payment option.
+ *
+ * @param array &$build
+ * The render array.
+ * @param \Drupal\Core\node\NodeInterface $node
+ * The node being rendered.
+ * @param $order
+ * Order data
+ * @param int $depth
+ * Recursion depth (internal use).
+ * @param int $max_depth
+ * Max recursion depth.
+ */
+function _turnstile_transform_body_recursive(array &$build, NodeInterface $node, array $order, $depth = 0, $max_depth = 20) {
+ if ($depth > $max_depth) {
+ return;
+ }
+
+ foreach ($build as $key => &$element) {
+ if (is_array($element)) {
+ // Check if this render array appears to be for the 'body' field.
+ if (
+ (isset($element['#field_name']) && $element['#field_name'] === 'body') ||
+ (isset($element['#type']) && $element['#type'] === 'processed_text' && isset($element['#text'])) ||
+ $key === 'body'
+ ) {
+ if ($node->hasField('body') && !$node->get('body')->isEmpty()) {
+ $body_field = $node->get('body')->first();
+
+ $summary = $body_field->summary;
+ $full = $body_field->value;
+ $format = $body_field->format;
+
+ // FIXME: use text_summary, or
+ // maybe better turnstile_truncate_content_safely? Not sure!
+ $replacement_text = $summary ?: text_summary($full, $format, 300);
+
+ // Replace with processed summary or trimmed text.
+ $element = [
+ '#type' => 'processed_text',
+ '#text' => $replacement_text . turnstile_render_payment_button ($order),
+ '#format' => $format,
+ '#cache' => ['contexts' => ['url.path']], // Optional caching metadata
+ ];
+ }
+ }
+ else {
+ // Recurse into the element.
+ _turnstile_transform_body_recursive($element, $node, $order, $depth + 1, $max_depth);
+ }
+ }
+ }
}
@@ -273,19 +318,15 @@ function turnstile_truncate_content_safely($content, $length = 200) {
/**
- * Render content preview with payment button.
+ * Render payment button.
*
- * @param string $body
- * The original body content.
* @param array $order_info
* Order information.
*
* @return string
- * Rendered preview with payment button.
+ * Rendered payment button.
*/
-function turnstile_render_preview_with_payment_button($body, $order_info) {
- // Safely truncate content to first few lines.
- $preview = turnstile_truncate_content_safely($body, 200);
+function turnstile_render_payment_button($order_info) {
\Drupal::logger('turnstile')->debug('Generating payment request body');
// FIXME: eventually, we may want to at least give the option to
@@ -297,9 +338,10 @@ function turnstile_render_preview_with_payment_button($body, $order_info) {
$payment_button .= '<a href="' . htmlspecialchars($order_info['payment_url']) . '" class="button btn btn-primary" style="display: inline-block; padding: 10px 20px; background: #007cba; color: white; text-decoration: none; border-radius: 4px;">Click here to open payment dialog</a>';
$payment_button .= '</div>';
- return $preview . $payment_button;
+ return $payment_button;
}
+
/**
* Implements hook_form_FORM_ID_alter() for node forms.
*/