Problem/Motivation
You're viewing a node. You have access to an entityqueue called "Favourites".
With the existing Entityqueue module you have to click on the Entityqueue tab, then add it to your queue called "Favourites"
Proposed resolution
Why not supply people with a block showing the queue names they have access to with a "+" or "-" in front?
I seem to recall this existed in the D7 version of either Nodequeue or Entityqueue.
Claude assures me it'll be as easy as 1, 2 3 (see the Claude solution further down).
But having an official solution, handling language and made by intelligent humans, might be preferable.
In Claude voice:
You're absolutely right, and I apologize for overlooking that crucial detail. Entity Queue indeed requires a CSRF token for security reasons in recent versions. Let's modify our approach to incorporate this token. Here's an updated implementation:
Update the route and controller:
In my_queue_module.routing.yml:
yamlCopymy_queue_module.add_to_queue:
path: '/node/{node}/add-to-queue/{queue_id}/{token}'
defaults:
_controller: '\Drupal\my_queue_module\Controller\QueueController::addToQueue'
_title: 'Add to Queue'
requirements:
_csrf_token: 'TRUE'
_permission: 'manipulate queues'
Update the QueueController.php:
phpCopy<?php
namespace Drupal\my_queue_module\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Access\CsrfTokenGenerator;
class QueueController extends ControllerBase {
protected $entityTypeManager;
protected $csrfToken;
public function __construct(EntityTypeManagerInterface $entity_type_manager, CsrfTokenGenerator $csrf_token) {
$this->entityTypeManager = $entity_type_manager;
$this->csrfToken = $csrf_token;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
$container->get('csrf_token')
);
}
public function addToQueue(NodeInterface $node, $queue_id, $token) {
if (!$this->csrfToken->validate($token, "add_to_queue:$queue_id:$node->id()")) {
$this->messenger()->addError($this->t('Invalid token.'));
return new RedirectResponse($node->toUrl()->toString());
}
$queue = $this->entityTypeManager->getStorage('entity_queue')->load($queue_id);
if ($queue) {
$queue->addItem($node);
$queue->save();
$this->messenger()->addMessage($this->t('Node added to queue.'));
}
else {
$this->messenger()->addError($this->t('Queue not found.'));
}
return new RedirectResponse($node->toUrl()->toString());
}
}
Create a custom Twig function to generate the token:
Create a new file src/TwigExtension/QueueTokenExtension.php:
phpCopy<?php
namespace Drupal\my_queue_module\TwigExtension;
use Drupal\Core\Access\CsrfTokenGenerator;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class QueueTokenExtension extends AbstractExtension {
protected $csrfToken;
public function __construct(CsrfTokenGenerator $csrf_token) {
$this->csrfToken = $csrf_token;
}
public function getFunctions() {
return [
new TwigFunction('generate_queue_token', [$this, 'generateQueueToken']),
];
}
public function generateQueueToken($queue_id, $node_id) {
return $this->csrfToken->get("add_to_queue:$queue_id:$node_id");
}
}
Register the Twig extension:
Create a new file my_queue_module.services.yml:
yamlCopyservices:
my_queue_module.twig.queue_token_extension:
class: Drupal\my_queue_module\TwigExtension\QueueTokenExtension
arguments: ['@csrf_token']
tags:
- { name: twig.extension }
Update the Twig template:
In your node.html.twig:
twigCopy{% if content.field_your_entityqueue_reference is empty %}
{% set queue_id = 'your_queue_machine_name' %}
{% set token = generate_queue_token(queue_id, node.id) %}
{{ link('Add to Queue', 'internal:/node/' ~ node.id ~ '/add-to-queue/' ~ queue_id ~ '/' ~ token, {'class':['button']}) }}
{% endif %}
These changes will:
Include a CSRF token in the URL.
Validate the token in the controller before adding the node to the queue.
Provide a custom Twig function to generate the token in the template.
Remember to:
Replace your_queue_machine_name with your actual queue machine name.
Clear the cache after making these changes.
Ensure the user still has the 'manipulate queues' permission.
This implementation should now work with the token requirement of Entity Queue. Would you like me to explain any part of this updated code in more detail?