Drupal 10: Creating A Homepage With The Config Pages Module

There are a number of different ways to create a homepage in Drupal. One common technique is to create a content type to store the fields you need, with the addition of blocks to add extra information to the homepage layout.

Adding a content type to handle the homepage has a number of problems. It can be tricky to set up the permissions correctly for users to edit the page, also, it's easy to for editors to accidentally delete it and break the entire site. You often have to protect the content in some way to prevent unwanted editing or deletion.

I was recently tasked with setting up a homepage of Drupal site and I decided to use a module called Config Pages to  allow a configurable homepage to be created. This approach turned out to be quite easy and was quickly adapted by the rest of the team to introduce extra configuration.

I thought I would detail the approach in an article taken since it requires a little bit of code but allows for quite a bit of flexibility.

Config pages is a module that allows the creation of single use fieldable entities. These can then be used to perform a number of tasks, including exposing configuration and creating singleton pages.

Setting up Config Pages

Once you have installed the module you need to create a config page type by going to the path at /admin/structure/config_pages/types and creating a new type. The settings page for creating these entities contains a few options, but we only really need the label. It is safe to ignore the fields about token, menu and context settings for the purposes of creating a homepage.

After you've created the type you can then configure it just like you would any other fieldable entity type. Just add the fields you need to the entity to handle all of the data you need to display.

For the purposes of this example I have created a type called "homepage", which has some simple fields for storing some text information and an image.

A Drupal site showing a config pages entity with fields.

Once that is in place we can now head to the path at /admin/structure/config_pages/homepage/edit, which will show us the edit page for the fields we just added. You can enter some data into this form and save it, which will create the entity in your database. The entity we create here is single use, meaning that it can't be duplicated or deleted, which makes it ideal for use as a homepage.

A Drupal site showing the edit interface for the homepage.

Note you can make the path to edit this entity a little bit nicer by entering the path into the Menu section on the homepage Config Page type configuration. The following example will change this route to be /homepage/edit, instead of /admin/structure/config_pages/homepage/edit.

The Drupal Config Pages configuration for the menu.

We can now save data to the homepage entity, but what about displaying that data? We need to add a little bit of custom code to get this working.

Adding Code For The Homepage

There is some code we need to add in order to get our Config Pages homepage working correctly. There isn't a lot of code that needs adding really, we just need to add a single controller action to a module that will render the homepage.

In a new module called mymodule, I created a mymodule.routing.yml file and added the following configuration.

mymodule.homepage:
  path: '/homepage'
  defaults:
    _title: 'Homepage'
    _controller: '\Drupal\mymodule\Controller\HomepageController::homepage'
  requirements:
    # Deliberately setting the access rights to be open as this is an example.
    _access: 'TRUE'

This means that if a user visits the page at /homepage the homepage() method in the HomepageController class should be called. All the homepage() method needs to do it load the homepage entity and render it, using the default view mode of "full".

If the homepage entity hasn't been created yet then we fall back to an simple message that just says "No content added".

Here is the code of the controller in full.

<?php

namespace Drupal\mymodule\Controller;

use Drupal\config_pages\Entity\ConfigPages;
use Drupal\Core\Controller\ControllerBase;

class HomepageController extends ControllerBase {

  public function homepage() {
    $configPage = ConfigPages::config('homepage');

    if ($configPage !== NULL) {
      $build = \Drupal::service('entity_type.manager')
        ->getViewBuilder('config_pages')
        ->view($configPage);
      $build['#cache']['tags'][] = 'homepage';
      return $build;
    }

    // Return an empty page with no cache.
    $build = [];
    $build['no_content_added'] = [
      '#markup' => '<p>No content added.</p>',
      '#cache' => [
        'tags' => [
          'homepage',
        ],
        'max-age' => 0,
      ],
    ];
    return $build;

  }

}

Once important thing to note in the above code is that we are adding a cache tag of "homepage" to the returned render array from the controller. This tag is important as when the homepage is updated we need to properly invalidate the cache so that the new data can be shown.

To invalidate this tag we need to create a hook_ENTITY_TYPE_update() hook that will listen for the homepage being updated and invalidate the correct tags.

/**
 * Implements hook_ENTITY_TYPE_update().
 */
function mymodule_config_pages_update(EntityInterface $entity) {
  if ($entity->bundle() === 'homepage') {
    // Invalidate tags when the homepage entity is updated.
    $tags = $entity->getCacheTagsToInvalidate();
    $tags[] = 'homepage';
    Cache::invalidateTags($tags);
  }
}

With this hook in place, any changes made to the homepage will be seen immediately.

If you have any views or other dynamic content being shown on the homepage then you will also need to inject the "homepage" tag into their cache tags to allow them to update the homepage cache correctly.

Local Tasks

Creating a coherent experience for editing the homepage is important, so adding local tasks configuration is a good idea. Local tasks allow your users to view the homepage and see an edit link that allows them to edit the page. Having this link is preferable to making your users hunt for the correct interface to edit the homepage within the Config Pages module.

To this end, I created a mymodule.links.task.yml file and added the following configuration to it.

mymodule.homepage:
  title: "Homepage"
  route_name: "mymodule.homepage"
  base_route: "mymodule.homepage"
mymodule.homepage_edit:
  title: "Edit"
  route_name: "config_pages.homepage"
  base_route: "mymodule.homepage"

The route for the homepage edit page is config_pages.homepage, so we just need to add this as an edit link that lives under the route we created for the controller action above.

That's it, we can now load the homepage via the path /homepage and see the content with the local tasks in action.

Here is a screenshot of this in action.

A Drupal site showing the fully built homepage.

This doesn't look amazing, but we'll come onto customising the theme later.

Drupal Front Page Configuration

With this code and configuration in place we can how update the Drupal default front page configuration to point at our /homepage path. This path is served by the controller we created earlier.

The Drupal homepage configuration dialog, configured to show the path /homepage.

With this done you can visit the homepage of your site and see the config page being rendered through the controller.

Permissions

It's worth taking a quick look at the permissions available for the Config Pages module. It comes with custom permissions for each entity you set up, so for the purposes of the homepage entity we just need to ensure that the correct users have permission to edit. The "Edit the Homepage config page entity" permission is used to allow this.

A Drupal site showing the config pages permissions section.

The permission to view the homepage config page entity doesn't matter too much as we are rendering the entity through the controller, which has it's own permissions through the route configuration.

Theme

The theme that comes with Config Pages just prints out the fields in the order they were set up in. This is fine, but it's a good idea to have more control over the theme.

Thankfully, the Config Pages module passes its rendering process through the Drupal template system, with the default template being called config-pages.html.twig. As we have called the Config Pages entity "homepage" we just need to create a template in our theme called config-pages--homepage.html.twig.

This is the content of the new template.

{#
/**
 * @file
 * Default theme implementation to display a config_page.
 *
 * @see template_preprocess_config_pages()
 *
 * @ingroup themeable
 */
#}
{%
  set classes = [
  'config_pages',
  'config_pages--type--' ~ config_pages.bundle|clean_class,
  view_mode ? 'config_pages--view-mode--' ~ view_mode|clean_class,
  view_mode ? 'config_pages--' ~ config_pages.bundle|clean_class ~ '--' ~ view_mode|clean_class,
]
%}
<div{{ attributes.addClass(classes) }}>

  <h1>{{ content.field_home_header_text }}</h1>
  <div>
    {{ content.field_homepage_banner_image }}
    {{ content.field_home_intro_text }}
  </div>

</div>

This is just a small template to show how to print out the individual components of the entity and can be expanded upon to create the theme you need.

You can also use a preprocess hook called template_preprocess_config_pages() to add additional items to your homepage theme. This is useful if you want to inject blocks or rendered views into your homepage content.

Conclusion

This is a fairly easy way to generate a homepage that can be adapted to any need you want just by altering the fields in your entity. The small amount of code needed to get this working allows for quite a bit of flexibility in the homepage setup. Once everything is set up the end result is quite effective.

As the entity we use to edit the homepage is configurable we can quickly launch any changes to the fields through the configuration management system.

The project I used this approach in actually had two config page entities created to display the homepage. This was done to separate the edit pages into different sections but also to allow one of those sections to be reused on other parts of the site. To get this working we used the template_preprocess_config_pages() hook to inject the additional config page into the template of the homepage, which worked really well.

If you want help with any of this then get in touch.

The only issue with this approach is that the homepage doesn't have revisioning. This means that if the homepage is changed there is no easy way to get back a previous version of it. It looks like there are some plans to make Config Pages revisionable, but that does rely on the new generic revisioning system coming to Drupal 10.1.x. If this is something you are looking for then feel free to contribute to that issue.

I should also note that the Config Pages Viewer module can be used to perform pretty much the same actions as the custom code additions here, but that module appears to be abandoned.

Comments

Nice article. Thanks for sharing

Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
4 + 8 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.