Render site alerts as part of the page content

Created on 17 June 2022, over 2 years ago
Updated 22 February 2023, about 2 years ago

First of all, big fan of the work done on the module so far, especially the features introduced in 2.x!
I just thought it was worth documenting a concern I had regarding performance/caching.

Problem/Motivation

Site alert and page filtering is currently handled on the frontend, however this has certain functionality/performance implications:

  1. Special internal routes and aliases such as /node/2, <front> aren't supported. Routing conditions should ideally be handled in the backend
  2. The AJAX callback returns site alert for every single page (including pages which aren't relevant to the user/current page), which isn't very scalable if there is a lot of site alerts
  3. An AJAX request is made on every page request, which shouldn't be necessary if appropriate cache tags/contexts are set on the initial site alert render added to the initial page content, should significantly reduce server overhead especially when site alerts are only required on specific pages.

Nice to have: Use Drupal.ajax() API rather than fetch() so that site AJAX behaviour is consistent. e.g. If the site requires non-standard authentication for backend requests.

Proposed resolution

Only site alerts relevant to the current route/page should be rendered and attached as part of the page just like a normal block would.

If full page caching is a concern, it can be implemented through the #lazy_builder API.

Whilst the page filtering can leverage Drupal's RequestPath \Drupal::service('plugin.manager.condition') Condition plugin.

And when processing site alert updates via AJAX in the controller, we can simply add the requested path to the request stack and let the Condition plugin do its work using logic along the lines of:

$requestStack = \Drupal::service('request_stack');
// Push the referring url onto the stack so that it can be filtered
// against. Keeping all the current request's cookies and sessions.
// Coming from "Drupal.url(drupalSettings.path.currentPath)"
$realPath = $current_request->request->get('currentPath', NULL);
if ($realPath) {
  $request = $current_request->duplicate([], [], [], NULL, [],
    [
      'REQUEST_METHOD' => 'GET',
      'REQUEST_URI' => $realPath,
    ] + $current_request->server->all());
  $requestStack->push($request);
}
// Renderer will handle filtering of site alerts using the Condition Plugin API.
$build = \Drupal::service('sitewide_alert.sitewide_alert_renderer')->build(
  // Coming from "drupalSettings.path.currentPathIsAdmin" (unsure if necessary)
  $current_request->request->get('currentPathIsAdmin', FALSE)
);
// Rest of the code ...
if ($realPath) {
  // Pop the pseudo request.
  $requestStack->pop();
}

Remaining tasks

Provide issue fork/patch.

User interface changes

Not visible to the user, but site alerts will now be stored as part of the page response (but hidden by default with a special class/style attribute), then the javascript will run through it to determine if it should be shown or not.

API changes

TBD

✨ Feature request
Status

Active

Version

2.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024