[Drupal 8] How to create blocks that present information from a custom settings form.

in #programming7 years ago

What Will I Learn ?

  • You will learn how to create a custom configuration form.
  • You will learn how to read information from a settings file and display it in a block.
  • You will learn how to create and place custom blocks.

Requirements

  • A Drupal 8 site, I will be using a fresh install
  • A text editor

Difficulty

  • Basic

Tutorial Contents

To start out I created the directory for the module and a few files for the various settings:

  • ms_copyright.info.yml
  • ms_copyright.module
  • ms_copyright.links.menu.yml
  • ms_copyright.routing.yml

file tree main files.PNG

I called my module ms_copyright so any time you see ms_copyright you should replace it with your module's name.


Now I'll explain what these files are for and how I structured them.

ms_copyright.info.yml

name: Copyright Module
description: Creates blocks to output the copyright and design credit messages
type: module
core: 8.x

The .info.yml file tells Drupal what the modules name, description, included files, and other information is. This is mostly used by the "Extend" screen that lists all of the modules installed.

ms_copyright.module

<?php ?>.
The .module file won't actually contain any code this time, so we'll open this file and fill it with empty php tags. This is normally where the module logic would go.

ms_copyright.routing.yml

ms_copyright.config:
    path: 'admin/config/ms_copyright/config'
    defaults:
        _form: '\Drupal\ms_copyright\Form\CopyrightSettingsForm'
        _title: 'Copyright Settings'
    requirements:
        _permission: 'administer site configuration'

The .routing.yml file tells Drupal where the configuration form can be found, and who can see it. The path sets the URL of the configuration page, while the _form tells drupal where in the module to find the code to build the form (This will be coming next). _permission tells Drupal who to allow to see the page, it is set so that only users with site configuration access can view it.

ms_copyright.links.menu.yml

ms_copyright.config:
    title: 'Copyright Settings'
    description: 'Settings for the copyright and design credit blocks.'
    parent: system.admin_config_system
    weight: 10
    route_name: ms_copyright.config

The .links.menu.yml file defines the menu link for the "Configuration" page in the administer menu (/admin/config). The title will be the link to the copyright form in the menu, and the description will be the sub-text underneath. The parent sets which group of menu links my module's link gets placed with and the weight determines it's place among them. Finally the route_name is set to use the route we defined in the .routing.yml.

Configuration menu.PNG

This is the result of the .links.menu.yml file

Configuration Form

Now that the base files are all set up we can start creating the custom form class. Drupal 8 looks for custom blocks in a very specific place, if you don't put the files there it won't find them. This means we have to create a new folder structure, src/Form/, to house the form class: CopyrightSettingsForm.php. This file will define how the configuration form will be built.

form folder structure.PNG

To start out create the CopyrightSettingsForm and have it extend ConfigBaseForm. Because we are extending ConfigBaseForm we need to define a few functions, and those functions will be all that is needed.

<?php

/**
 * @file
 * Contains \Drupal\ms_copyright\Form\CopyrightSettingsForm
 */

namespace Drupal\ms_copyright\Form;

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

class CopyrightSettingsForm extends ConfigFormBase
{
    /**
    * {@inheritdoc}
    */
    public function getFormId()
    {
        return 'copyright_settings_form';
    }

    /**
    * {@inheritdoc}
    */
    public function buildForm(array $form, FormStateInterface $form_state)
    {
        // Default text values
        $holder = 'Maple Storm';
        $credit = 'Website design by Maple Thunder';
        $form = parent::buildForm($form, $form_state);
        
        // Grab the configuration file
        $config = $this->config('ms_copyright.settings');
            
        // Set the active variables to display to either
        // the config value, or the default value
        if($config->get('ms_copyright.copyright_holder'))
            $holder = $config->get('ms_copyright.copyright_holder');
        
        if($config->get('ms_copyright.design_credit'))
            $credit = $config->get('ms_copyright.design_credit');


        // Use drupals form api to build the fields of the form.
        $form['copyright_title'] = array(
            '#type' => 'label',
            '#value' => '<h2>Copyright Holder</h2>',
        );

        $form['copyright_holder'] = array(
            '#type' => 'textfield',
            '#value' => $holder,
        );

        $form['design_credit_title'] = array(
            '#type' => 'label',
            '#value' => '<h2>Design Credit</h2>',
        );

        $form['design_credit'] = array(
            '#type' => 'textarea',
            '#value' => $credit,
        );

        return $form;
    }
  
     /**
     * {@inheritdoc}
     */
    public function submitForm(array &$form, FormStateInterface $form_state)
    {
        // Grab the config file
        $config = $this->config('ms_copyright.settings');
        // Save the values in the fields to the config file
        $config->set('ms_copyright.copyright_holder', $form_state->getValue('copyright_holder'));
        $config->set('ms_copyright.design_credit', $form_state->getValue('design_credit'));
        // Save the config file
        $config->save();

        return parent::submitForm($form, $form_state);
    }

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

Entire CopyrightSettingForm.php class

Ok, I know that was a lot of code to just throw out there so I'll go over it a bit. The getFormId and getEditableConfigNames functions are used to return the unique ID of the form and return the editable config file's name respectively.

The buildForm function is what handles the layout of the form, and uses the form api to do it. I wanted to have a default value available so that if there is nothing found in the config file it will still have something to display. So I set a couple default strings, checked to see if the config had values for the fields, and if it didn't I used the default strings.

The submitForm function fires when the submit button on the form is pressed. In this function I save the values from the form fields into the config file and run the code the base class has in it's submitForm function with return parent::submitForm($form, $form_state);


Time for the displays

In each of these classes there only needs to be a build() function. This function is where I will put all of the code to generate the block display. They will both extend the BlockBase class so I have to include a reference to the class with a use statement at the top of each.

CopyrightBlock.php

<?php

namespace Drupal\ms_copyright\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
* Provides a 'Copyright' Block.
*
* @Block(
*   id = "ms_copyright_block",
*   admin_label = @Translation("Copyright block"),
*   category = @Translation("Copyright"),
* )
*/
class CopyrightBlock extends BlockBase
{

  /**
   * {@inheritdoc}
   */
  public function build()
  {
    // Set the correct config reference
    $config = \Drupal::config('ms_copyright.settings');
    
      // Grab necessary vars
      $year = date('Y');
      $copyright_symbol = '&#169;&nbsp;';
      $company_name = $config->get('ms_copyright.copyright_holder');

      // Build block markup
      $block_content = '';
      $block_content .= '<div class="col-xs-12 col-sm-6">';
          $block_content .= $copyright_symbol . $year . ' ' . $company_name;
      $block_content .= '</div>';

      $block = array(
          '#markup' => $block_content,
      );

    return $block;
  }

}

For the copyright block I save the current year using date('Y'), a reference to the copyright symbol with a space after it, and the copyright holder text from the configuration file. Once I have all of these set to variables for easier use I start to build my markup.

When I'm manually building html markup in php like this I like to format it as shown, line by line and indenting in the html style. It's unnecessary, I could have put it all in a single string on one line but I find the format I use to be easier to read and debug.

DesignCreditBlock.php

<?php

namespace Drupal\ms_copyright\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
* Provides a 'Design Credit' Block.
*
* @Block(
*   id = "rs_design_credit_block",
*   admin_label = @Translation("Design Credit block"),
*   category = @Translation("Red Sky"),
* )
*/
class DesignCreditBlock extends BlockBase
{
  /**
   * {@inheritdoc}
   */
  public function build()
  {
    // Set the correct config reference
    $config = \Drupal::config('ms_copyright.settings');
    
    $credit = $config->get('ms_copyright.design_credit');

      // Build block markup
      $block_content = '';
      $block_content .= '<div class="col-xs-12 col-sm-6">';
          $block_content .= $credit;
      $block_content .= '</div>';

      $block = array(
          '#markup' => $block_content,
      );

    return $block;
  }

}

The design credit block is very similar to the copyright block, the only difference being which variable in the configuration file gets referenced.


Placement

Now it's time to get those block displaying on a page. Find your way to the Block Layout page (/admin/structure/block), and scroll to the region you want to place the block in. I'll be using the Footer Fifth region. Click on the "Place Block" button next to the region name, then find the block you want to add and click the Place block button.

In the configuration modal for the block uncheck the Display title option so the titles will be hidden. Some blocks may want to use this feature, but I only want the text that was entered into the configuration file to display.

configure block.PNG

I almost always hide the block titles.

After doing this for both blocks, I made sure they were ordered how I wanted them. Copyright block, then display credit block.

block layout.PNG

The order in the list will determine the order they appear in the html.

When you go to the front page you can see the result.

final product.PNG

Sort:  

I hate programming.I got D grade in my programming course but love to see your devotion.I think you love programing and thanks for sharing knowledge with your steem friends :)