Skip to content

Customization Guide

Learn how to customize and extend the Entityqueue Form Widget for advanced use cases.

Overview

The Entityqueue Form Widget is built on Drupal's form API and hooks system, making it flexible and extensible. This guide covers common customization scenarios.

Form Alteration

Modifying the Widget with Hook Alter

The widget can be customized using standard Drupal form alter hooks.

Hide Specific Queues

Scenario: Hide certain queues from some users or content types

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Target node forms only
  if (strpos($form_id, 'node_') !== 0 || strpos($form_id, '_edit_form') === false) {
    return;
  }

  // Hide specific queue from widget
  if (isset($form['entityqueue_form_widget']['queue_id_5'])) {
    $form['entityqueue_form_widget']['queue_id_5']['#access'] = false;
  }
}

Modify Queue Labels

Scenario: Change queue labels dynamically

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    if (isset($form['entityqueue_form_widget'])) {
      foreach ($form['entityqueue_form_widget'] as $queue_id => &$queue_element) {
        if (is_array($queue_element) && isset($queue_element['#title'])) {
          // Add custom context to title
          $queue_element['#title'] .= ' [Featured]';
        }
      }
    }
  }
}

Add Help Text to Queues

Scenario: Provide guidance to editors about queue purposes

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_article_edit_form') === 0) {
    if (isset($form['entityqueue_form_widget']['queue_featured'])) {
      $form['entityqueue_form_widget']['queue_featured']['#description'] =
        'Check this box to feature this article on the homepage. Only 5 articles can be featured at a time.';
    }
  }
}

Form Submission Handling

Custom Processing on Save

Scenario: Execute custom logic when queues are assigned

/**
 * Implements hook_form_submit().
 */
function mymodule_form_submit(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
  $form_id = $form_state->getFormObject()->getFormId();

  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    $node = $form_state->getFormObject()->getEntity();

    // Get queue assignments
    $queues_assigned = [];
    if (isset($form['entityqueue_form_widget'])) {
      foreach ($form['entityqueue_form_widget'] as $queue_id => $queue_element) {
        if (is_numeric($queue_id) &&
            isset($form_state->getValue(['entityqueue_form_widget', $queue_id])) &&
            $form_state->getValue(['entityqueue_form_widget', $queue_id])) {
          $queues_assigned[] = $queue_id;
        }
      }
    }

    // Execute custom logic
    if (!empty($queues_assigned)) {
      // Trigger custom event, send notification, etc.
      \Drupal::moduleHandler()->invokeAll('node_featured', [$node, $queues_assigned]);
    }
  }
}

Theming and Display

Customize Widget Display

Alter Widget HTML

Scenario: Change widget HTML structure or classes

{# In your theme's templates directory #}
{# templates/form/entityqueue_form_widget.html.twig #}

<fieldset class="form-group form-group--entityqueues{{ attributes.class }}">
  {% if legend_title %}
    <legend class="fieldset__legend">
      <span class="fieldset__legend-span">{{ legend_title }}</span>
    </legend>
  {% endif %}

  <div class="fieldset__description">
    Assign this content to queues to feature it in specific sections.
  </div>

  <div class="form-section form-section--entityqueues">
    {% for key, child in children %}
      {% if key|first != '#' %}
        <div class="form-item--checkbox form-item--entityqueue">
          {{ child }}
        </div>
      {% endif %}
    {% endfor %}
  </div>
</fieldset>

Add CSS Classes

Scenario: Style specific queues differently

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    if (isset($form['entityqueue_form_widget'])) {
      $form['entityqueue_form_widget']['#attributes']['class'][] = 'entityqueue-widget-custom';
    }
  }
}

Conditional Display

Show/Hide Widget Based on Conditions

By User Role

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    $user = \Drupal::currentUser();

    // Hide widget from non-editors
    if (!$user->hasPermission('edit entityqueues')) {
      if (isset($form['entityqueue_form_widget'])) {
        $form['entityqueue_form_widget']['#access'] = false;
      }
    }
  }
}

By Content Field Value

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_article_edit_form') === 0) {
    $node = $form_state->getFormObject()->getEntity();

    // Only show featured queue for premium content
    if ($node->get('field_premium')->value) {
      // Show widget
    } else {
      if (isset($form['entityqueue_form_widget']['queue_featured'])) {
        unset($form['entityqueue_form_widget']['queue_featured']);
      }
    }
  }
}

Integration with Other Modules

Integration with Workflows

Scenario: Show/hide queues based on workflow state

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    $node = $form_state->getFormObject()->getEntity();

    // Only allow featured queue for published content
    if ($node->hasField('moderation_state')) {
      $state = $node->get('moderation_state')->value;

      if ($state !== 'published') {
        if (isset($form['entityqueue_form_widget']['queue_featured'])) {
          $form['entityqueue_form_widget']['queue_featured']['#disabled'] = true;
          $form['entityqueue_form_widget']['queue_featured']['#description'] =
            'Content must be published before featuring.';
        }
      }
    }
  }
}

Integration with Field Permissions

Scenario: Respect field-level permissions on queues

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'node_') === 0 && strpos($form_id, '_edit_form') !== false) {
    if (isset($form['entityqueue_form_widget'])) {
      // Check each queue's field permissions
      foreach ($form['entityqueue_form_widget'] as $queue_id => &$element) {
        if (is_numeric($queue_id)) {
          $queue = Queue::load($queue_id);

          // Check custom field permissions
          if (!current_user_can_edit_queue_field($queue)) {
            $element['#access'] = false;
          }
        }
      }
    }
  }
}

JavaScript Customization

Enhance Widget Interactions

Scenario: Add custom behavior to queue checkboxes

// In your custom module JS file
(function (Drupal) {
  'use strict';

  /**
   * Custom behavior for entityqueue form widget.
   */
  Drupal.behaviors.entityqueueCustom = {
    attach: function (context, settings) {
      // Find widget checkboxes
      const checkboxes = context.querySelectorAll('.entityqueue-checkbox');

      checkboxes.forEach(checkbox => {
        // Add change event listener
        checkbox.addEventListener('change', function() {
          const queueId = this.getAttribute('data-queue-id');
          const isChecked = this.checked;

          // Custom behavior
          if (isChecked) {
            // Queue was checked
            this.parentElement.classList.add('is-queued');
            Drupal.announce('Added to queue: ' + queueId);
          } else {
            // Queue was unchecked
            this.parentElement.classList.remove('is-queued');
            Drupal.announce('Removed from queue: ' + queueId);
          }
        });
      });
    }
  };
})(Drupal);

Add Visual Feedback

// Validate queue assignments before submission
(function (Drupal) {
  Drupal.behaviors.validateEntityqueues = {
    attach: function(context, settings) {
      const form = context.querySelector('form');

      if (!form) return;

      form.addEventListener('submit', function(e) {
        const checkedQueues = form.querySelectorAll('.entityqueue-checkbox:checked');

        if (checkedQueues.length === 0) {
          const result = confirm('No queues selected. Continue anyway?');
          if (!result) {
            e.preventDefault();
          }
        }
      });
    }
  };
})(Drupal);

Programmatic Queue Management

Add Content to Queues via Code

use Drupal\entityqueue\Entity\EntitySubqueue;

/**
 * Add a node to a queue programmatically.
 */
function mymodule_add_to_queue($node_id, $queue_id) {
  $queue = \Drupal\entityqueue\Entity\EntityQueue::load($queue_id);

  if (!$queue) {
    throw new \Exception("Queue $queue_id not found");
  }

  $subqueue = $queue->getSubqueue(0);

  if (!$subqueue) {
    // Create subqueue if doesn't exist
    $subqueue = EntitySubqueue::create([
      'queue' => $queue->id(),
    ]);
    $subqueue->save();
  }

  // Add item to queue
  $items = $subqueue->get('items')->getValue();
  $items[] = ['target_id' => $node_id];

  $subqueue->set('items', $items);
  $subqueue->save();
}

Remove Content from Queues via Code

/**
 * Remove a node from a queue programmatically.
 */
function mymodule_remove_from_queue($node_id, $queue_id) {
  $queue = \Drupal\entityqueue\Entity\EntityQueue::load($queue_id);

  if (!$queue) {
    throw new \Exception("Queue $queue_id not found");
  }

  $subqueue = $queue->getSubqueue(0);

  if (!$subqueue) {
    return;
  }

  $items = $subqueue->get('items')->getValue();
  $items = array_filter($items, function($item) use ($node_id) {
    return $item['target_id'] != $node_id;
  });

  $subqueue->set('items', $items);
  $subqueue->save();
}

Advanced Hooks

Custom Hook: Queue Assignment

Define custom hook in your module:

/**
 * Implement custom queue assignment hook.
 *
 * @param \Drupal\node\Entity\Node $node
 *   The node being assigned to queues.
 * @param array $queue_ids
 *   Array of queue IDs the node is being assigned to.
 */
function hook_queue_node_assigned($node, $queue_ids) {
  // Custom implementation
}

Invoke in your module:

\Drupal::moduleHandler()->invokeAll('queue_node_assigned', [$node, $queue_ids]);

Next Steps