Learn Drupal Quicly

Welcome to the Drupal Learning Hub. Learn the core concepts of building powerful, content-managed websites. (This page is powered by a reusable JavaScript library.)

 

[
    {
        "groupTitle": "Section 1: Core Concepts",
        "topics": [
            {
                "title": "What is Drupal?",
                "explanation": "Drupal is an advanced, open-source **Content Management System (CMS)**. It's a tool for building websites and applications. It is known for its power, flexibility, and security. It is built on PHP, SQL (like MySQL), and other technologies.",
                "example": "Drupal is not just a website builder; it's a 'content framework'.\nIt's used to build complex sites for:\n- Universities (e.g., Harvard)\n- Governments (e.g., The White House)\n- Large corporations and media"
            },
            {
                "title": "Node (Content)",
                "explanation": "A **Node** is the most fundamental piece of content in Drupal. Think of it as a single 'post' or 'page'.\n\nAn 'About Us' page is a node. A 'Blog Post' is a node. A 'Product' is a node. Each node has a unique ID (NID).",
                "example": "You write a new blog post titled \"My First Day\".\nThis entire post (title, body, image, tags) is stored as a single 'node' with an ID like 'node/1'."
            },
            {
                "title": "Content Types (Structure)",
                "explanation": "A **Content Type** is a *template* or 'blueprint' for a node. It defines what *fields* a node will have.\n\nDrupal comes with two content types by default: 'Article' and 'Basic Page'. You can create your own.",
                "example": "Content Type: 'Article'\n- Title (Text field)\n- Body (Long text field)\n- Image (Image field)\n- Tags (Taxonomy field)\n\nContent Type: 'Event' (Custom)\n- Title (Text field)\n- Event Date (Date field)\n- Location (Text field)\n- Description (Long text field)"
            },
            {
                "title": "Fields",
                "explanation": "A **Field** is a single piece of data in a Content Type. Drupal gives you many field types (text, number, image, date, file, etc.). You add fields to content types to build your structure. This is Drupal's most powerful feature.",
                "example": "You are creating a 'Staff Profile' content type.\nYou would add fields like:\n- field_full_name (Text)\n- field_job_title (Text)\n- field_profile_picture (Image)\n- field_bio (Long Text)"
            },
            {
                "title": "Blocks",
                "explanation": "A **Block** is a 'chunk' of content that can be placed in a specific area of your site. Unlike a 'node' (which is a main page), a block is usually smaller and reusable.\n\nExamples: a login form, a search bar, a 'Who's Online' list.",
                "example": "You have a \"Search\" block.\nYou can tell Drupal to place this one block in the \"Header\" region, so it appears on every single page of your website."
            },
            {
                "title": "Regions",
                "explanation": "A **Region** is a defined area in your site's *theme* where you can place *blocks*. Your theme defines all its available regions.",
                "example": "A typical theme has regions like:\n- Header\n- Primary Menu\n- Sidebar Left\n- Content (This is where your 'node' content goes)\n- Sidebar Right\n- Footer\n\nYou place your \"Search\" block into the \"Header\" region."
            },
            {
                "title": "Taxonomy",
                "explanation": "**Taxonomy** is Drupal's system for categorizing and tagging content. A 'Vocabulary' is a collection of 'Terms'.",
                "example": "You create a Vocabulary called \"Blog Categories\".\nInside it, you add Terms like:\n- \"Technology\"\n- \"Health\"\n- \"Travel\"\n\nYou then add a \"Taxonomy Reference\" field to your 'Article' content type, so you can tag each post."
            },
            {
                "title": "Views",
                "explanation": "**Views** is a powerful query builder. It's a UI for fetching content from the database and displaying it as a list, grid, table, etc. This is a core part of Drupal.\n**You do not need to write SQL.**",
                "example": "You want to create your website's homepage.\nYou use Views to create a 'View' that:\n1. SHOWS: Content\n2. OF TYPE: Article\n3. SORTED BY: Post Date (Newest first)\n4. DISPLAYS: 10 items\n5. AS A: List of 'Teasers'\n6. AT THE URL: /home"
            },
            {
                "title": "Menus",
                "explanation": "Drupal has a built-in system for creating and managing navigation menus. You can add links to nodes, external URLs, or Views pages.",
                "example": "You have a 'Main navigation' menu.\nYou add links to it:\n- \"Home\" (path: /home)\n- \"About Us\" (path: /node/1)\n- \"Blog\" (path: /blog)\n- \"Google\" (path: https://google.com)"
            }
        ]
    },
    {
        "groupTitle": "Section 2: Site Management",
        "topics": [
            {
                "title": "Themes",
                "explanation": "A **Theme** controls the 'look and feel' (the design) of your Drupal site. It is the skin of the site and includes all the CSS, JavaScript, and HTML structure (template files).",
                "example": "Drupal has a core theme (like 'Olivero').\nYou can download thousands of free 'contrib' themes from Drupal.org.\nYou can also build your own custom theme for a unique design."
            },
            {
                "title": "Modules (Core vs. Contrib)",
                "explanation": "A **Module** is a set of code that adds *functionality* to your site.\n• **Core Modules:** Bundled with Drupal (e.g., Views, Block, Taxonomy). You just need to enable them.\n• **Contrib Modules:** Modules written by the community that you download and install to add new features.",
                "example": "Core: You enable the 'Views' module.\nContrib: You want an Instagram feed on your site. You download and install the 'Instagram Block' module."
            },
            {
                "title": "Users, Roles, & Permissions",
                "explanation": "Drupal has a very granular permission system.\n• **User:** A single account (e.g., 'admin', 'alice').\n• **Role:** A 'group' of users (e.g., 'Editor', 'Subscriber').\n• **Permission:** A single action (e.g., 'Create Article content', 'Delete any user').\nYou assign permissions to roles, and roles to users.",
                "example": "You create a Role called 'Editor'.\nYou give this Role the permissions:\n- \"Article: Create new content\"\n- \"Article: Edit own content\"\nYou do *not* give it \"Administer site configuration\".\nThen, you assign the 'Editor' role to user 'bob'."
            },
            {
                "title": "The Admin Toolbar",
                "explanation": "The 'Admin Toolbar' is the black bar at the top of the site that you see when you are logged in as an administrator. It is your main tool for navigating the 'back end' of Drupal.",
                "example": "The toolbar has top-level links like:\n- Content (Add/find content)\n- Structure (Manage Blocks, Content Types, Menus, Views)\n- Appearance (Manage Themes)\n- Extend (Manage Modules)\n- Configuration (Site settings)\n- People (Manage Users)\n- Reports (Logs)"
            }
        ]
    },
    {
        "groupTitle": "Section 3: Development Tools (CLI)",
        "topics": [
            {
                "title": "What is Composer?",
                "explanation": "In modern Drupal (8+), **Composer** is the standard way to manage your project. It is a command-line tool for PHP that installs and updates Drupal core and all your contrib modules.",
                "example": "You install Drupal using Composer.\nTo add a new module, you run a command in your terminal:\n\ncomposer require drupal/pathauto\n\nThis downloads the 'pathauto' module and its dependencies."
            },
            {
                "title": "What is Drush?",
                "explanation": "**Drush (Drupal Shell)** is a command-line tool that lets you manage your Drupal site from the terminal. It is much faster for common admin tasks than clicking through the UI.",
                "example": "Common Drush commands:\n\n// Clear all of Drupal's caches\ndrush cr\n\n// Install a module (after downloading it)\ndrush en views_ui\n\n// Uninstall a module\ndrush pmu views_ui\n\n// Get a one-time login link for the admin user\ndrush uli"
            }
        ]
    },
    {
        "groupTitle": "Section 4: Custom Theming (Frontend)",
        "topics": [
            {
                "title": "Creating a Theme",
                "explanation": "To create a theme, you create a folder in `/themes/custom/my_theme` and add a `.info.yml` file. This file defines the theme's name, description, and its layout 'regions'.",
                "example": "# /themes/custom/my_theme/my_theme.info.yml\n\nname: 'My Custom Theme'\ntype: 'theme'\ncore_version_requirement: '^9 || ^10'\n\nregions:\n  header: 'Header'\n  content: 'Content'\n  sidebar: 'Sidebar'\n  footer: 'Footer'"
            },
            {
                "title": "Creating a Sub-theme",
                "explanation": "A **sub-theme** is the best practice. It *inherits* all the templates and styles from a 'base theme' (like Drupal's default 'Olivero' or 'Claro'). You only change the parts you need to.\nYou define this in your `.info.yml` file.",
                "example": "# /themes/custom/my_subtheme/my_subtheme.info.yml\n\nname: 'My Sub-theme'\ntype: 'theme'\ncore_version_requirement: '^9 || ^10'\n\n# This is the key that makes it a sub-theme:\nbase_theme: 'olivero'"
            },
            {
                "title": "Twig Templates",
                "explanation": "**Twig** is the templating engine used by Drupal to render HTML. It's fast, secure, and flexible. You can override any default Drupal template (like `node.html.twig`) by copying it into your theme's `/templates` folder and editing it.",
                "example": "<article{{ attributes }}>\n  <h2>{{ label }}</h2>\n  <div class=\"my-custom-class\">\n    {{ content }}\n  </div>\n</article>"
            },
            {
                "title": "Libraries (`.libraries.yml`)",
                "explanation": "This is the *only* correct way to add CSS and JavaScript to your theme or module. You define a 'library' in a `my_theme.libraries.yml` file, and then 'attach' that library to a template or page.",
                "example": "# my_theme.libraries.yml\nglobal-styling:\n  css:\n    theme:\n      css/style.css: {}\n  js:\n    js/script.js: {}\n  dependencies:\n    - core/jquery # Tells Drupal this needs jQuery"
            }
        ]
    },
    {
        "groupTitle": "Section 5: Custom Module Dev (Backend)",
        "topics": [
            {
                "title": "Creating a Module",
                "explanation": "To create a custom module, you only need two things: a folder and one file.\n1. Create a folder in `/modules/custom/my_module`.\n2. Inside, create a file named `my_module.info.yml`. This file tells Drupal your module exists.",
                "example": "# /modules/custom/my_module/my_module.info.yml\n\nname: 'My Custom Module'\ntype: 'module'\ndescription: 'Does a cool custom thing.'\ncore_version_requirement: '^9 || ^10'"
            },
            {
                "title": "Hooks",
                "explanation": "A **Hook** is the 'classic' Drupal way for modules to *alter* Drupal's behavior. It's a PHP function you name in a specific way (e.g., `hook_form_alter`) that Drupal will automatically find and run at the right time.",
                "example": "// In my_module.module file\n\n/**\n * Implements hook_form_alter().\n */\nfunction my_module_form_alter(&$form, $form_state, $form_id) {\n  // This code will run for EVERY form on the site\n  if ($form_id == 'user_login_form') {\n    // Add a custom message to the user login form\n    $form['message'] = [\n      '#markup' => '<p>Welcome! Please log in.</p>',\n    ];\n  }\n}"
            },
            {
                "title": "Routing & Controllers",
                "explanation": "This is the 'modern' (Symfony) way to create a **new page** with code. You define a 'route' in a `my_module.routing.yml` file, which maps a URL to a 'Controller'. The Controller is a PHP class that returns the content for that page.",
                "example": "# my_module.routing.yml\nmy_module.hello_page:\n  path: '/hello'\n  defaults:\n    # Points to the 'content' method in our Controller\n    _controller: '\\Drupal\\my_module\\Controller\\HelloController::content'\n  requirements:\n    _permission: 'access content'"
            },
            {
                "title": "Controller Class",
                "explanation": "A Controller is a PHP class that handles a request from a Route. Its method returns a 'render array', which is Drupal's way of describing content that needs to be themed.",
                "example": "// /src/Controller/HelloController.php\nnamespace Drupal\\my_module\\Controller;\n\nclass HelloController {\n  public function content() {\n    // This is a render array\n    return [\n      '#markup' => 'Hello, world! This is my page.'\n    ];\n  }\n}"
            },
            {
                "title": "Form API (Intro)",
                "explanation": "Drupal's Form API lets you define complex forms using PHP arrays. Drupal handles the HTML rendering, security, and submission for you. You create a Form by extending the `FormBase` class.",
                "example": "// In /src/Form/MyForm.php\nclass MyForm extends FormBase {\n  public function getFormId() { return 'my_module_my_form'; }\n\n  public function buildForm(array $form, FormStateInterface $form_state) {\n    $form['first_name'] = [\n      '#type' => 'textfield',\n      '#title' => 'First Name',\n    ];\n    $form['submit'] = [\n      '#type' => 'submit',\n      '#value' => 'Save',\n    ];\n    return $form;\n  }\n  // ... (You also need a submitForm() method)\n}"
            }
        ]
    },
    {
        "groupTitle": "Section 6: Advanced Concepts",
        "topics": [
            {
                "title": "Plugin System",
                "explanation": "The Plugin system is the 'modern' Drupal way to create reusable pieces of functionality. Many things in Drupal are plugins: **Blocks**, Field Formatters, and Views filters.\n\nYou create a new Block by creating a 'Block Plugin' class.",
                "example": "// In /src/Plugin/Block/MyBlock.php\n/**\n * @Block(\n * id = \"my_module_my_block\",\n * admin_label = @Translation(\"My Custom Block\")\n * )\n */\nclass MyBlock extends BlockBase {\n  public function build() {\n    return [\n      '#markup' => 'This content is from my plugin!'\n    ];\n  }\n}"
            },
            {
                "title": "Entities",
                "explanation": "An **Entity** is the core abstract object for data. A **Node** is an entity. A **User** is an entity. A **Taxonomy Term** is an entity. A **Comment** is an entity.\nThey all share a common API for creating, loading, saving, and deleting.",
                "example": "// Using code to load a node entity\n$node = \\Drupal\\node\\Entity\\Node::load(1);\n\n// Get the title\n$title = $node->getTitle();\n\n// Set a new title\n$node->setTitle('A New Title');\n$node->save();"
            },
            {
                "title": "Render Arrays",
                "explanation": "Render Arrays are the 'magic' of Drupal's theme system. You almost *never* write HTML directly in PHP. Instead, you build a structured PHP array that *describes* the content, and Drupal's theme layer turns it into HTML. This makes it 'renderable' and 'alterable'.",
                "example": "$page = [\n  '#type' => 'page',\n  'header' => [\n    '#type' => 'markup',\n    '#markup' => '<h1>My Page Title</h1>',\n  ],\n  'content' => [\n    '#markup' => '<p>Hello world.</p>',\n  ],\n];"
            },
            {
                "title": "Services & Dependency Injection",
                "explanation": "This is an advanced, but essential, Symfony concept. A **Service** is any object that performs a 'global' task (like sending an email or logging a message). **Dependency Injection** is the *only* proper way to use these services in your module or class. You list the services you need, and Drupal 'injects' them for you.",
                "example": "// DO NOT DO THIS (wrong):\n$user = \\Drupal::currentUser();\n\n// DO THIS (Dependency Injection):\n// 1. Define your service in my_module.services.yml\n// 2. In your class constructor, 'inject' it:\npublic function __construct(AccountInterface $currentUser) {\n  $this->currentUser = $currentUser;\n}\n// Now use it:\n$this->currentUser->id();"
            },
            {
                "title": "Drush for Developers",
                "explanation": "Drush is even more powerful for developers. You can use it to generate 'scaffolding' (starter code) for modules, themes, plugins, and more.",
                "example": "// Generate a new module 'my_new_module'\ndrush generate module\n\n// Generate a new block plugin inside 'my_module'\ndrush generate plugin:block\n\n// Rebuild caches (after code changes)\ndrush cr"
            },
            {
                "title": "Configuration Management",
                "explanation": "This system is for syncing changes between environments (e.g., from your Dev site to your Prod site). Any change you make in the UI (like creating a View or a new field) is stored as a **YAML file**. You can commit these YAML files to git and 'import' them on your production site.",
                "example": "// 1. Make a change on your dev site.\n// 2. Export the change to a YAML file:\ndrush config:export\n\n// 3. Commit and push the file with git.\n// 4. On your prod site, pull the file and import it:\ndrush config:import"
            }
        ]
    }
]