Cheatsheets / Drupal

Drupal Cheatsheet

Complete Drupal reference. Hit Ctrl+P to print.

Drush Commands

drush statusShow Drupal installation status
drush en module_nameEnable a module
drush pmu module_nameUninstall (disable) a module
drush pm:list --status=enabledList all enabled modules
drush updbRun pending database updates
drush crRebuild all caches (cache:rebuild)
drush cc renderClear render cache only
drush cexExport active configuration to sync directory
drush cimImport configuration from sync directory
drush cdiffShow diff between active and sync config
drush uliGenerate one-time admin login URL
drush user:create bob --mail=bob@example.com --password=secretCreate a new user
drush user:role:add administrator bobAdd role to user
drush sql:dump > backup.sqlExport database to file
drush sql:cli < backup.sqlImport database from file
drush sql:query "SELECT * FROM users_field_data LIMIT 5"Run SQL query
drush php:eval "echo Drupal::VERSION;"Execute PHP in Drupal context
drush watchdog:showShow recent log messages
drush queue:run my_queueProcess items in a queue
drush deployStandard deployment: updatedb, cim, cr

Entities & Nodes

\Drupal\node\Entity\Node::load($nid)Load a node by ID
\Drupal::entityTypeManager()->getStorage("node")->load($nid)Load via entity type manager
\Drupal::entityTypeManager()->getStorage("node")->loadMultiple([1, 2, 3])Load multiple entities
$node->get("title")->valueGet field value
$node->get("field_image")->entityGet referenced entity from field
$node->set("title", "New Title"); $node->save()Update and save a field
Node::create(["type" => "article", "title" => "Hello", "status" => 1])->save()Create and save new node
$node->delete()Delete an entity
$node->toUrl()->toString()Get canonical URL for entity
$node->isPublished() / $node->setPublished()Check/set published status
\Drupal\user\Entity\User::load(\Drupal::currentUser()->id())Load fully-loaded current user
\Drupal::currentUser()->hasPermission("administer nodes")Check current user permission

Entity Query

\Drupal::entityQuery("node")Start an entity query
->condition("type", "article")Filter by bundle (content type)
->condition("status", 1)Filter by published status
->condition("field_category.entity.name", "News")Filter by referenced entity field
->condition("uid", \Drupal::currentUser()->id())Filter by author
->sort("created", "DESC")Order by field direction
->range(0, 10)Limit results (offset, count)
->accessCheck(TRUE)Enforce entity access checks (required in D10+)
->execute()Run query - returns array of IDs
\Drupal::entityTypeManager()->getStorage("node")->loadMultiple($nids)Load results from query
->count()->execute()Get count only
->orConditionGroup()Create an OR condition group

Hooks

function mymodule_node_presave(NodeInterface $node) { }Fires before a node is saved
function mymodule_node_insert(NodeInterface $node) { }Fires after new node is saved
function mymodule_node_update(NodeInterface $node) { }Fires after existing node is updated
function mymodule_node_delete(NodeInterface $node) { }Fires after node is deleted
function mymodule_entity_presave(EntityInterface $entity) { }Fires before any entity is saved
function mymodule_form_alter(&$form, FormStateInterface $state, $form_id) { }Alter any form
function mymodule_form_node_article_edit_form_alter(&$form, ...) { }Alter a specific form by ID
function mymodule_theme() { return ["my_template" => ["variables" => ["items" => []]]]; }Register a Twig template
function mymodule_preprocess_node(&$variables) { }Preprocess variables for node templates
function mymodule_install() { }Runs on module install
function mymodule_update_N() { }Database/config update hook (N = number)
function mymodule_cron() { }Runs during cron

Forms API

class MyForm extends FormBase { public function getFormId() { return "my_form"; } }Implement FormBase
public function buildForm(array $form, FormStateInterface $form_state): array { }Build the form array
$form["name"] = ["#type" => "textfield", "#title" => "Name", "#required" => TRUE]Text field element
"#type" => "select", "#options" => ["a" => "Option A", "b" => "Option B"]Select element
"#type" => "checkboxes", "#options" => [...]Checkboxes element
"#type" => "submit", "#value" => "Save"Submit button
"#default_value" => $form_state->getValue("name")Set default value
public function validateForm(array &$form, FormStateInterface $form_state): void { }Validation handler
$form_state->setErrorByName("name", "Name is required.")Set validation error on field
public function submitForm(array &$form, FormStateInterface $form_state): void { }Submit handler
$form_state->getValue("name")Get submitted field value
$form_state->setRedirectUrl(Url::fromRoute("entity.node.canonical", ["node" => $nid]))Redirect after submit

Services & Dependency Injection

\Drupal::service("module_handler")Get a service from the container (procedural)
\Drupal::database()Get database service
\Drupal::cache("render")Get a cache bin
\Drupal::logger("my_module")->info("Message: @var", ["@var" => $value])Log a message
\Drupal::messenger()->addStatus("Saved.")Display a status message
\Drupal::config("system.site")->get("name")Read config value
\Drupal::configFactory()->getEditable("mymodule.settings")->set("key", $val)->save()Write config value
mymodule.services.ymlRegister services in module services YAML file
services: mymodule.my_service: class: Drupal\mymodule\MyService arguments: ["@entity_type.manager"]Service definition with argument
public function __construct(protected EntityTypeManagerInterface $entityTypeManager) { }Inject service in constructor
public static function create(ContainerInterface $container) { return new static($container->get("entity_type.manager")); }Factory method for DI

Twig Theming

{{ variable }}Output a variable (auto-escaped)
{{ variable|raw }}Output unescaped HTML
{{ content.field_image }}Render a field (use content array in node templates)
{{ node.title.value }}Access raw field value directly
{% if variable %} ... {% endif %}Conditional
{% for item in items %} ... {% endfor %}Loop
{% extends "@classy/node/node.html.twig" %}Extend a base template
{% block content %} ... {% endblock %}Override a block
{% include "@mymodule/partials/card.html.twig" with {title: node.label} %}Include partial with variables
{{ path("entity.node.canonical", {node: node.id}) }}Generate URL in Twig
{{ url("<front>") }}Generate front-page URL
{{ "Hello @name"|t({"@name": name}) }}Translated string with placeholder
node--article.html.twigTemplate for article content type
node--article--full.html.twigTemplate for article in full view mode
field--field-image.html.twigTemplate for a specific field

Configuration Management

drush cex && git add config/Export config and commit to version control
drush cimImport config from sync directory to active storage
$config_dir = \Drupal::service("config.storage.sync")Access config sync storage service
config/sync/system.site.ymlDefault sync directory for exported config
config/install/mymodule.settings.ymlConfig installed with module
config/schema/mymodule.schema.ymlSchema for module config (enables translation)
\Drupal::config("system.site")->get("name")Read simple config immutably
\Drupal::configFactory()->getEditable("mymodule.settings")->set("key", $val)->save()Read-write config
drush config:get system.siteView config object values
drush config:set system.site name "New Name"Set a config value from CLI