Drush Commands
drush statusShow Drupal installation statusdrush en module_nameEnable a moduledrush pmu module_nameUninstall (disable) a moduledrush pm:list --status=enabledList all enabled modulesdrush updbRun pending database updatesdrush crRebuild all caches (cache:rebuild)drush cc renderClear render cache onlydrush cexExport active configuration to sync directorydrush cimImport configuration from sync directorydrush cdiffShow diff between active and sync configdrush uliGenerate one-time admin login URLdrush user:create bob --mail=bob@example.com --password=secretCreate a new userdrush user:role:add administrator bobAdd role to userdrush sql:dump > backup.sqlExport database to filedrush sql:cli < backup.sqlImport database from filedrush sql:query "SELECT * FROM users_field_data LIMIT 5"Run SQL querydrush php:eval "echo Drupal::VERSION;"Execute PHP in Drupal contextdrush watchdog:showShow recent log messagesdrush queue:run my_queueProcess items in a queuedrush deployStandard deployment: updatedb, cim, crEntities & 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 fieldNode::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 permissionEntity 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 groupHooks
function mymodule_node_presave(NodeInterface $node) { }Fires before a node is savedfunction mymodule_node_insert(NodeInterface $node) { }Fires after new node is savedfunction mymodule_node_update(NodeInterface $node) { }Fires after existing node is updatedfunction mymodule_node_delete(NodeInterface $node) { }Fires after node is deletedfunction mymodule_entity_presave(EntityInterface $entity) { }Fires before any entity is savedfunction mymodule_form_alter(&$form, FormStateInterface $state, $form_id) { }Alter any formfunction mymodule_form_node_article_edit_form_alter(&$form, ...) { }Alter a specific form by IDfunction mymodule_theme() { return ["my_template" => ["variables" => ["items" => []]]]; }Register a Twig templatefunction mymodule_preprocess_node(&$variables) { }Preprocess variables for node templatesfunction mymodule_install() { }Runs on module installfunction mymodule_update_N() { }Database/config update hook (N = number)function mymodule_cron() { }Runs during cronForms API
class MyForm extends FormBase { public function getFormId() { return "my_form"; } }Implement FormBasepublic 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 valuepublic function validateForm(array &$form, FormStateInterface $form_state): void { }Validation handler$form_state->setErrorByName("name", "Name is required.")Set validation error on fieldpublic 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 submitServices & 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 valuemymodule.services.ymlRegister services in module services YAML fileservices: mymodule.my_service: class: Drupal\mymodule\MyService arguments: ["@entity_type.manager"]Service definition with argumentpublic function __construct(protected EntityTypeManagerInterface $entityTypeManager) { }Inject service in constructorpublic static function create(ContainerInterface $container) { return new static($container->get("entity_type.manager")); }Factory method for DITwig 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 placeholdernode--article.html.twigTemplate for article content typenode--article--full.html.twigTemplate for article in full view modefield--field-image.html.twigTemplate for a specific fieldConfiguration Management
drush cex && git add config/Export config and commit to version controldrush cimImport config from sync directory to active storage$config_dir = \Drupal::service("config.storage.sync")Access config sync storage serviceconfig/sync/system.site.ymlDefault sync directory for exported configconfig/install/mymodule.settings.ymlConfig installed with moduleconfig/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 configdrush config:get system.siteView config object valuesdrush config:set system.site name "New Name"Set a config value from CLI