Add CSS to a custom Drupal 10 theme tutorial

This tutorial will guide you through the steps of adding CSS styling to a custom Drupal 10 theme.

  1. Start with a Drupal 10 base theme (you’ll need to rename the theme)
  2. Add a css folder to the theme’s folder
    
    # File Structure
    core
    modules
    profiles
    sites
    themes
    --contrib
    --custom
    ----d10_custom_theme_add_css
    ------css
    --------style.css
    ------d10_custom_theme_add_css.info.yml 
    ------d10_custom_theme_add_css.libraries.yml 
    
  3. Add a style.css file in the css folder
    
    /**
    * @file
    * D10 custom theme global style CSS file.
    *
    * Enter any custom CSS below this comment.
    */
    
    .custom-class {
        color: fff;
    }
    
  4. Add a d10_custom_theme_add_css.libraries.yml file to the theme’s folder
    
    # d10_custom_theme_add_css.libraries.yml 
    global-styling:
        css:
        theme:
            css/style.css: {}
    
  5. Add the libraries: mapping scalar and sequence to the d10_custom_theme_add_css.info.yml file
    
    # d10_custom_theme_add_css.info.yml
    name: D10 Custom Theme (add css)
    type: theme
    description: 'A Drupal 10 custom theme base with custom css.'
    core_version_requirement: '^10'
    base theme: 'false'
    libraries:
        - d10_custom_theme_add_css/global-styling
    regions:
        header: 'Header'
        content: 'Content'
        sidebar_first: 'Sidebar first'
        footer: 'Footer''
    
  6. Congratulations! You now have a custom theme with custom css.

More information

Create a basic custom Drupal 10 theme tutorial

This tutorial will give you everything you need to create a very basic custom theme for Drupal 10. It will just show up as an available theme in Drupal and not much more.

  1. Create a folder named d10_custom_theme_base inside the themes/custom/ folder of your Drupal 10 installation.
    
    core
    modules
    profiles
    sites
    themes
    --contrib
    --custom
    ----d10_custom_theme_base
    
  2. Save a text file with the name d10_custom_theme_base.info.yml inside the created folder.
  3. Edit the d10_custom_theme_base.info.yml file to include the following:
    
    name: D10 Custom Theme Base
    type: theme
    description: 'A Drupal 10 custom theme base.'
    core_version_requirement: '^10'
    base theme: 'false'
    regions:
        header: 'Header'
        content: 'Content'
        sidebar_first: 'Sidebar first'
        footer: 'Footer'
    
  4. Congratulations! You have a custom theme.

More information

How to limit the Drupal 8 & 9 Content view to show only editable content

Thankfully, there is a module for that, but the documentation isn’t great.

  1. Install the Views Node Access Filter module
  2. Edit the Content view (URL: example.com/admin/structure/views/view/content, UI Path: Structure > Views > Content > Edit)
    Views Node Access Filter module view edit
  3. With Default display selected, click add a Filter Criteria
    Views Node Access Filter module add filter
  4. Check Editable and click Add and configure filter criteria
    Views Node Access Filter Module Editable
  5. Click Apply
    Views Node Access Filter Module Apply
  6. Save the view
    Views Node Access Filter Module Save

Now the Content view will only show the user the content that they are able to edit.

Custom Module Configuration

Drupal 8 & 9 Custom Module with Configuration or Setting Page

So you have been building a custom module. Congradulations! This is a big step, but now you want more. You would like to be able to have a configuration page so that you can set some settings particular to your module. This tutorial will give you the very basics to get you a configuration page for your custom module.

Here are the building block you will need and some assumptions of what you will start off with.

  • Building blocks
    • Basic custom module
    • CustomModuleForm.php
    • custom_module.routing.yml
    • custom_module.schema.yml
  • Assumptions
    • You already have at least a basic Drupal site up and running
    • You have access to the files that make up the site
    • You can edit these files with a text editor
    • You have at least a basic custom module already set up

You can get all the completed code on the Custom Module Configuration repository on gitub.

Building blocks

Basic Custom Module

If you don’t have a module already please create one first before going through these instructions. It will make a lot more sense about what actually is needed to add a configuration page. Visit the Drupal 9 Basic Custom Module page on this site for building you own custom module.

CustomModuleForm.php

For you to save a configuration you need some way to gather the information. The CustomModuleForm.php is a very important piece to the puzzle. This file will be stored in a subdirectory of your custom module (e.g., /docroot/sites/default/modules/custom/custom_module/src/Form/CustomModuleForm.php). This file is used to build the form that you will use to enter your desired configuration.

You need the following parts to this file in order for your form to work:

  • Form class
  • Methods of the class
    • getEditableConfigNames() – gets the configuration name
    • getFormId() – returns the form’s unique ID
    • buildForm() – returns the form array
    • validateForm() – validates the form
    • submitForm() – processes the form submission

Form class

The form class is the basis of the form. There is some configuration before the class to get everything needed to get the form available in the right space. All the methods in this section will be within this class. Here is a complete file.

<?php

/**
 * @file
 * Contains Drupal\custom_module\Form\CustomModuleForm.
 */

namespace Drupal\custom_module\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

class CustomModuleForm extends ConfigFormBase {
	// Methods below and code go in this class
}

getEditableConfigNames()

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'custom_module.settings',
    ];
  }

getFormId()

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'custom_module_form';
  }

validateForm()

This function has to be here but currently it is not validating anything for simplicity.

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

  }

submitForm()

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $this->config('custom_module.settings');
    $config->set('custom_module.custom_module_settings', $form_state->getValue('custom_module_settings'));
    $config->save();
    return parent::submitForm($form, $form_state);
  }

custom_module.schema.yml

Let drupal know where to save the configuration in the database with the schema file located at /docroot/sites/default/modules/custom/custom_module/config/schema/custom_module.schema.yml.

custom_module.settings:
  type: config_object
  label: 'Custom module settings'
  mapping:
    policy_library:
      type: mapping
      mapping:
        custom_module_settings:
          type: text
          label: 'Custom module settings'

custom_module.routing.yml

The routing.yml file is stored in the root directory of your custom module file structure at /docroot/sites/default/modules/custom/custom_module/. Like most of the other files in this folder it starts off with the custom module name. In this case it is custom_module. So the full file path is /docroot/sites/default/modules/custom/custom_module/custom_module.routing.yml.

The custom_module.routing.yml file, in this case, is going to tell Drupal that there is a page at /admin/config/development/custom-module. That page will have a form, title, and a required permission to access it.

custom_module.form:
  path: '/admin/config/development/custom-module'
  defaults:
    _form: '\Drupal\custom_module\Form\CustomModuleForm'
    _title: 'Custom Module settings'
  requirements:
    _permission: 'administer site configuration'

custom_module.links.menu.yml

The full path of the links.menu.yml file is /docroot/sites/default/modules/custom/custom_module/custom_module.links.menu.yml. This file lets Drupal know that there should be a menu item under the Home > Administration > Configuration > Development menu structure with these settings.

custom_module.form:
  title: 'Custom module settings'
  description: 'Configure settings for the custom module.'
  route_name: custom_module.form
  parent: 'system.admin_config_development'

Drupal 8 & 9 check if current page is user

You may want to check programmatically if you are on a user page or profile in Drupal 8 or 9. Use Drupal’s routeMatch to grab user. Then check if $user is an instance of user. Execute your code on that page.

$user = \Drupal::routeMatch()->getParameter('user');
if ($user instanceof \Drupal\user\UserInterface) {
  // It's a user page!
}

Migration From Drupal 7 to Drupal 8: How do I find which items were ignored?

You are migrating from Drupal 7 to Drupal 8 and you have ignored items after you run a migration. This leads to the very important question of which ones were ignored?

What you see

[notice] Processed 632 items (630 created, 0 updated, 0 failed, 2 ignored) - done with 'node_form'

The above is what I will use in my examples.

What you want to know

What are the items ignored!? For this we can look into the database. I assume you have access to a console…

The migrate_map_migration_name table in your database will give you the information you need. There will be a column named source_row_status. The value of 2 equals the status of ignored. So run the following MySQL command:

SELECT * FROM `migrate_map_node_form` WHERE source_row_status = 2;

The sourceid1 column of the returned rows will contain the id of the item that was ignored.

Example output:

source_ids_hash sourceid1 destid1 source_row_status source_row_status last_imported hash
8530eb5d63ad4cfea47134a28e3339e089f639164d218287c3… 10931 NULL 2 0 0
ddd550e747c2a26a2a5058d49be0e146616fd5c45f6bef88f3… 11656 NULL 2 0 0

Answers on stackoverflow.

Migration of Files from Dupal 7 to Drupal 8 with: [notice] Field discovery failed for Drupal core version 7. Did this site have the CCK or Field module installed? Error: No database connection configured for source plugin d7_field_instance

When migrating files in Drupal 7 to Drupal 8 you receive one or more notices:

[notice] Field discovery failed for Drupal core version 7. Did this site have the CCK or Field module installed? Error: No database connection configured for source plugin d7_field_instance

At the end of the migration you will see something like this:

[notice] Processed 2607 items (2474 created, 0 updated, 15 failed, 118 ignored) - done with 'file'

The numbers will be different according to the amount of files you are migrating. In my case each of the 118 ignored files all had generated [notice] Field discovery failed....

After looking through the database I found that one of my fields held reference data to a user that no longer existed.

Process I took to find the problem

  1. Google and Drupal site
    1. There was very little information to be found with searching for: [notice] Field discovery failed for Drupal core version 7. Did this site have the CCK or Field module installed? Error: No database connection configured for source plugin d7_field_instance.
  2. Dive into the database – splash
    1. Find which files didn’t get migrated from the migration map with MYSQL on the D8 database.
      SELECT * FROM `migrate_map_file` where source_row_status <> 0;
      
      You’ll want to note that all the files that don’t have a d8_database > migrate_map_file > migrate_map_status of 0 are not created. The status of 2 means the file is ignored and 3 means it failed the migration.
    2. Use MYSQL on the D7 database to select a few files each that were ignored and created.
      SELECT * FROM `file_managed` WHERE fid = 5981 OR fid = 6051 OR fid = 5816 OR fid = 6906 OR fid = 16231 OR fid = 3709
      
      The file_managed table is where you can pull each FID (field id) from the fid column. In the example the last two FIDs where files that were created. The other 3 FIDs where ones that had been ignored. By comparing these I found that the only thing that stood out was the UIDs (user ids). A couple of the files ignored had the same UID.
    3. On the Drupal 7 site I viewed the user by the UID (mysite.com/user/123). This ended up in a page not found. You can also check this in the database with the following command.
      SELECT * FROM `users` WHERE uid = 123;
      

Conclusion

There were files with an author that no longer existed in the database. As an example, the file with the FID of 5981. This file referenced the author, which was a user, with a UID of 123 that was no longer in the database. This caused the notice and for the file to be ignored in the migration.

Drupal 8: Missing Login

Drupal 8: What happened to my login page!?

The Short

If you are working on the page.html.twig file and you now can’t get to the login screen confirm you are rendering the content section in your template by having {{ page.content }} in the page.html.twig file.

The Long

Recently, I have been learning to use Drupal 8 while at the same time getting more and more familiar with Drupal 7. I hit a little problem along the way and thought I would share as Drupal is notoriously hard to find information on when you need it. Unfortunately, part of the reason why is because if you read the documentation you can figure it out with some effort.

Who wants to put that kind of effort into it when it seems like there is a simple fix? So here is a simple fix or something you can check if you have a similar problem.

What I was doing…

I was in the process of building a custom theme and was building a template using YOURTHEME/templates/page.html.twig.

After logging out I was unable to log back in. I tried logging in via the login path built into Drupal 8 (mysite.com/user/login). It came up with the same page as the main page I was working on. I determined the template was the problem by renaming the template so as not to be rendered by Drupal. Note you can’t clear the cache if you can’t login. You will have to run the drush in the command line in the root folder (the folder with sites in it…) of your site: drush cr. Now the login page work by going to mysite.com/user/login.

The problem was that I had defined the content area in the MYTHEME.info.yml but did not add the code to the template to render the content in the content area of my theme. To resolve enter {{ page.content }} where you want to render your login information in your theme. Clear the all caches and change the name of the template back to what it was (page.html.twig).