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

in #programming7 years ago

What Will I Learn ?

<ul> <li>You will learn how to create a custom configuration form. <li>You will learn how to read information from a settings file and display it in a block. <li>You will learn how to create and place custom blocks. <h2>Requirements <ul> <li>A Drupal 8 site, I will be using a fresh install <li>A text editor <h2>Difficulty <ul> <li>Basic <h2>Tutorial Contents <p dir="auto">To start out I created the directory for the module and a few files for the various settings: <ul> <li>ms_copyright.info.yml <li>ms_copyright.module <li>ms_copyright.links.menu.yml <li>ms_copyright.routing.yml <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmaYCPuYEuDjphgzsuLZWXo1tXM1iXscJ4wnrSAbRP2AkB/file%20tree%20main%20files.PNG" alt="file tree main files.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmaYCPuYEuDjphgzsuLZWXo1tXM1iXscJ4wnrSAbRP2AkB/file%20tree%20main%20files.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmaYCPuYEuDjphgzsuLZWXo1tXM1iXscJ4wnrSAbRP2AkB/file%20tree%20main%20files.PNG 2x" /> <blockquote> <p dir="auto">I called my module <em>ms_copyright so any time you see <em>ms_copyright you should replace it with your module's name. <hr /> <p dir="auto">Now I'll explain what these files are for and how I structured them. <h4>ms_copyright.info.yml <pre><code>name: Copyright Module description: Creates blocks to output the copyright and design credit messages type: module core: 8.x <p dir="auto">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. <h4>ms_copyright.module <p dir="auto"><code><?php ?>.<br /> 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. <h4>ms_copyright.routing.yml <pre><code>ms_copyright.config: path: 'admin/config/ms_copyright/config' defaults: _form: '\Drupal\ms_copyright\Form\CopyrightSettingsForm' _title: 'Copyright Settings' requirements: _permission: 'administer site configuration' <p dir="auto">The <em>.routing.yml file tells Drupal where the configuration form can be found, and who can see it. The <em>path sets the URL of the configuration page, while the <em>_form tells drupal where in the module to find the code to build the form (This will be coming next). <em>_permission tells Drupal who to allow to see the page, it is set so that only users with site configuration access can view it. <h4>ms_copyright.links.menu.yml <pre><code>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 <p dir="auto">The <em>.links.menu.yml file defines the menu link for the "Configuration" page in the administer menu (/admin/config). The <em>title will be the link to the copyright form in the menu, and the description will be the sub-text underneath. The <em>parent sets which group of menu links my module's link gets placed with and the <em>weight determines it's place among them. Finally the <em>route_name is set to use the route we defined in the <em>.routing.yml. <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmakvbYzjWYQyw8V9ADCWkFNJHQ9U5M8V9hV79zPNbZFKF/Configuration%20menu.PNG" alt="Configuration menu.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmakvbYzjWYQyw8V9ADCWkFNJHQ9U5M8V9hV79zPNbZFKF/Configuration%20menu.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmakvbYzjWYQyw8V9ADCWkFNJHQ9U5M8V9hV79zPNbZFKF/Configuration%20menu.PNG 2x" /> <blockquote> <p dir="auto">This is the result of the <em>.links.menu.yml file <h4>Configuration Form <p dir="auto">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, <code>src/Form/, to house the form class: <code>CopyrightSettingsForm.php. This file will define how the configuration form will be built. <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmXnzFEjWLK6D8TRjAwXV3ZfjzBdys1AGjex8zny6BygCW/form%20folder%20structure.PNG" alt="form folder structure.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmXnzFEjWLK6D8TRjAwXV3ZfjzBdys1AGjex8zny6BygCW/form%20folder%20structure.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmXnzFEjWLK6D8TRjAwXV3ZfjzBdys1AGjex8zny6BygCW/form%20folder%20structure.PNG 2x" /> <p dir="auto">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. <pre><code><?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', ]; } } <blockquote> <p dir="auto">Entire CopyrightSettingForm.php class <p dir="auto">Ok, I know that was a lot of code to just throw out there so I'll go over it a bit. The <em>getFormId and <em>getEditableConfigNames functions are used to return the unique ID of the form and return the editable config file's name respectively. <p dir="auto">The <em>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. <p dir="auto">The <em>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 <em>submitForm function with <code>return parent::submitForm($form, $form_state); <hr /> <h3>Time for the displays <p dir="auto">In each of these classes there only needs to be a <code>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 <em>use statement at the top of each. <h4>CopyrightBlock.php <pre><code><?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; } } <p dir="auto">For the copyright block I save the current year using <code>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. <p dir="auto">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. <h4>DesignCreditBlock.php <pre><code><?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; } } <p dir="auto">The design credit block is very similar to the copyright block, the only difference being which variable in the configuration file gets referenced. <hr /> <h3>Placement <p dir="auto">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 <em>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 <em>Place block button. <p dir="auto">In the configuration modal for the block uncheck the <em>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. <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmbj5Vca2KgxzrZUHDxAy5DN7mbmfrzBmcgMTGQH8cn9zM/configure%20block.PNG" alt="configure block.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmbj5Vca2KgxzrZUHDxAy5DN7mbmfrzBmcgMTGQH8cn9zM/configure%20block.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmbj5Vca2KgxzrZUHDxAy5DN7mbmfrzBmcgMTGQH8cn9zM/configure%20block.PNG 2x" /> <blockquote> <p dir="auto">I almost always hide the block titles. <p dir="auto">After doing this for both blocks, I made sure they were ordered how I wanted them. Copyright block, then display credit block. <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmURVBJDbr1JpkJxxWkacgv8F1tWhGpx8ZT44isRMs4goi/block%20layout.PNG" alt="block layout.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmURVBJDbr1JpkJxxWkacgv8F1tWhGpx8ZT44isRMs4goi/block%20layout.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmURVBJDbr1JpkJxxWkacgv8F1tWhGpx8ZT44isRMs4goi/block%20layout.PNG 2x" /> <blockquote> <p dir="auto">The order in the list will determine the order they appear in the html. <p dir="auto">When you go to the front page you can see the result. <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmWJoFtK8egyEe9vjcRZQPFRgBeg9umiVzXBG9JzGJ2wW2/final%20product.PNG" alt="final product.PNG" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmWJoFtK8egyEe9vjcRZQPFRgBeg9umiVzXBG9JzGJ2wW2/final%20product.PNG 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmWJoFtK8egyEe9vjcRZQPFRgBeg9umiVzXBG9JzGJ2wW2/final%20product.PNG 2x" />
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 :)