Chaos Tool Suite (ctools)

A comprehensive suite of APIs and tools that improve the developer experience in Drupal, providing utilities for plugins, forms, AJAX, contexts, and more.

ctools
469,499 sites
214
drupal.org

Install

Drupal 11 v4.1.0
composer require 'drupal/ctools:^4.1'
Drupal 10, 9 v4.0.5
composer require 'drupal/ctools:^4.0'

Overview

The Chaos Tool Suite (ctools) is primarily a set of APIs and tools designed to improve the developer experience in Drupal. It provides a powerful collection of utilities and helper functions that other modules can leverage to build complex functionality.

CTools offers a Form Wizard API for creating multi-step forms, a Context API for wrapping objects in unified wrappers, typed data resolution services, block display variant management, and AJAX modal dialog support. It also provides enhanced condition plugins with constraint support and tempstore utilities for caching data across multiple page requests.

The module is commonly used as a dependency by other major Drupal modules such as Panels, Page Manager, and various Layout Builder extensions. End users typically interact with ctools indirectly through modules that depend on it, while developers use its APIs directly to build advanced functionality.

Features

  • Form Wizard API - A comprehensive system for creating multi-step forms with automatic step tracking, previous/next navigation, AJAX support, and SharedTempStore integration for preserving values across requests
  • Context API - Tools for wrapping objects (entities, typed data) in unified context wrappers and providing an API to create, manipulate, and accept these contexts as input
  • Typed Data Resolver - Service for resolving typed data relationships and converting property paths to context objects, enabling navigation through complex entity relationships
  • Block Display Variant - Abstract base class for display variants that contain and manage blocks with full context awareness and region management
  • Relationship Plugin System - A complete plugin manager for creating and managing relationships between entities and typed data properties
  • AJAX Modal Dialog Support - Trait and command classes for easily creating AJAX-enabled modal dialogs and wizard forms
  • Enhanced Condition Plugins - Extended EntityBundle condition with constraint support that can apply and remove bundle constraints from contexts
  • Tempstore Utilities - Services for caching edited objects across multiple page requests, enabling complex multi-form editing workflows
  • Entity View Block - Dynamically generated blocks for viewing any entity type in any available view mode
  • Plugin Collection Classes - BlockPluginCollection and VariantPluginCollection for managing collections of block and variant plugins

Use Cases

Creating Multi-Step Configuration Wizards

Use the FormWizardBase class to create multi-step configuration forms. Extend the class, implement getOperations() to define your steps (each with a title and form class), and set up routes using the wizard controllers. The wizard automatically handles step navigation, value caching in SharedTempStore, AJAX modal support, and provides customizable 'Previous/Next/Finish' buttons. This is commonly used by modules like Page Manager and Panels for creating complex page configurations.

Displaying Entity Fields as Blocks

Enable the ctools_block submodule to gain access to field blocks for every entity type. These blocks can be placed in any block region and will display a single field from an entity using the context system. Configure the formatter and label display per block instance. Useful for creating flexible layouts where individual fields need to be placed independently.

Enhancing Views Block Configuration

Enable the ctools_views submodule to gain additional configuration options when placing Views blocks. In the view's block display settings, enable the desired 'Allow settings' options (items per page, offset, pager type, hide/sort fields, configure/disable filters, configure sorts). When the block is placed, administrators can override these settings per-instance, allowing a single view to be reused with different configurations across the site.

Building Context-Aware Display Systems

Use the TypedDataResolver and ContextMapper services to build systems that can navigate entity relationships and provide context-aware functionality. The resolver can convert token-style paths like 'node:uid:name' into proper context objects with values. This enables building dynamic content that adapts based on the current page context, similar to Panels and Page Manager functionality.

Creating Modal Dialog Forms

Use the AjaxFormTrait and OpenModalWizardCommand to create AJAX-powered modal dialog forms. The trait provides helper methods for generating AJAX attributes, while the command can open wizard forms in modal dialogs. This is useful for inline editing interfaces or configuration dialogs that don't require a full page reload.

Implementing Custom Relationship Plugins

Create custom Relationship plugins by implementing RelationshipInterface and using the @Relationship annotation. Relationships define how to navigate from one context to another (e.g., from a node to its author). The RelationshipManager discovers plugins in the Plugin/Relationship directory. This is essential for building systems that need to access related data based on the current context.

Applying Dynamic Constraints to Contexts

Use the ConstraintConditionInterface implemented by EntityBundle to dynamically add or remove constraints from contexts. When a condition is evaluated, it can modify the context's constraints (e.g., limiting a node context to specific content types). This enables building flexible access control and content filtering systems that adapt based on condition configuration.

Creating Preview/Temporary Entities

Enable the ctools_entity_mask submodule and define an entity type with a 'mask' key pointing to another entity type. The mask entity will inherit all fields and display configuration from the masked type but uses a storage handler that doesn't persist data. This is ideal for building preview systems or configuration forms that need to render entities without saving them.

Tips

  • When extending FormWizardBase, override getOperations() to define your wizard steps. Each step should have a 'form' key with the fully qualified class name of the form and optionally a 'title' key for the step label.
  • Use the ctools.wizard.factory service's getWizardForm() method with the third parameter set to TRUE to enable AJAX modal support for your wizards.
  • The deprecated ctools.serializable.tempstore.factory service should be replaced with Drupal core's tempstore.shared service. The functionality is identical.
  • When using ctools_views, configure the 'Allow settings' options in the view's block display before placing the block. Only enabled settings will appear in the block configuration form.
  • The EntityBundle condition in ctools adds constraint support that core's condition lacks. If you need to apply bundle constraints to contexts programmatically, use applyConstraints() method.
  • For entity view blocks, be aware of recursion protection - if you try to display an entity within its own view, the block will return empty to prevent infinite loops.
  • The TypedDataResolver's convertTokenToContext() method can navigate deep property paths like 'node:uid:field_profile:entity' to access nested relationships.

Technical Details

Hooks 2
hook_ctools_relationship_info_alter

Allows modules to alter the relationship plugin definitions discovered by the RelationshipManager.

hook_condition_info_alter (used by ctools)

CTools uses this hook to replace core's entity bundle condition classes with its enhanced versions that support constraints.

Troubleshooting 5
Wizard form loses values between steps

Ensure your wizard class properly implements getTempstoreId() and getMachineName(). Values are stored in SharedTempStore using these identifiers. Also verify that your form's submitForm() method doesn't overwrite the cached values incorrectly.

Entity field blocks not appearing in block library

Enable the ctools_block submodule. Note that these blocks are intentionally hidden from Layout Builder - they appear in the standard block placement interface but not in Layout Builder's block browser.

Views block configuration options not showing

First, ensure ctools_views is enabled. Then edit the view and go to the block display settings. Under 'Allow settings', enable the specific options you want to configure per-block (items per page, offset, hide fields, etc.).

Condition constraints not being applied

Verify your condition plugin implements ConstraintConditionInterface. Call applyConstraints() with your contexts array after configuring the condition. Remember to call removeConstraints() when the condition is removed or reconfigured.

Modal wizard dialogs not opening

Ensure core/drupal.dialog.ajax library is attached. The OpenModalWizardCommand handles this automatically, but if using manual AJAX calls, you need to attach the library. Also verify your link has the correct AJAX attributes from AjaxFormTrait::getAjaxAttributes().

Security Notes 3
  • The SerializableTempstoreFactory is deprecated. Migrate to core's SharedTempStoreFactory which has been audited for security.
  • When implementing custom wizards, ensure proper access checks are in place for each step. The TempstoreAccess service can help validate access to tempstore-based routes.
  • Be cautious with the TypedDataResolver when exposing relationship navigation to end users - it could potentially reveal data structure information if not properly restricted.