Improve performance of module with improved image style flush logic

Created on 2 July 2025, 5 days ago

Problem/Motivation

When adding a new media image or editing an existing media image all image styles are deleted. This can cause a large performance issue as all the derivative images need to be rebuilt which is an expensive process and if you have many images using the same image style on a page this can lead to a server timeout.

Steps to reproduce

  • Setup this module with focal point and create a single image style that uses focal point.
  • Create a page content type and add a media contextual reference field that allows unlimited media references.
  • Add in 20-30 images to the field and then every time we add a new image and save the page the image styles will be deleted causing Drupal to recreate ALL the image derivatives. This then causes our production server (Pantheon.io) to have a server timeout issue

Proposed resolution

Limit the deletion of the image styles to a path for a specific media item instead of the whole folder of image styles

Current code deleting whole image style folder

  /**
   * Flush contextuals derivative of the style.
   *
   * @param \Drupal\image\Entity\ImageStyle $imageStyle
   *   Image Style.
   */
  public function flushStyle(ImageStyle $imageStyle) {
    $folder_uri = 'public://contextual/styles/' . $imageStyle->id();
    $this->fileSystem->deleteRecursive($folder_uri);
  }

Purposed code to just target an individual media image

  /**
   * Flush contextual derivative of the style.
   *
   * @param \Drupal\image\Entity\ImageStyle $imageStyle
   *   Image Style.
   * @param string|null $path
   *   (optional) The original image path or URI. If supplied, only derivatives
   *   for this specific image will be flushed.
   */
  public function flushStyle(ImageStyle $imageStyle, $path = NULL) {
    if ($path !== NULL) {
      // Only flush derivatives for this specific image path.
      // Build the contextual path pattern for this specific image.
      $scheme = $this->streamWrapperManager::getScheme($path);
      $target = $this->streamWrapperManager::getTarget($path);
      $target_as_folder = str_replace('.', '__', $target);
      
      $contextual_folder = 'public://contextual/styles/' . $imageStyle->id() . '/' . $scheme . '/' . $target_as_folder;
      
      // Only delete the specific contextual derivatives for this image.
      if (is_dir($contextual_folder)) {
        $this->fileSystem->deleteRecursive($contextual_folder);
      }
    }
  }
Feature request
Status

Active

Version

2.1

Component

Code

Created by

🇨🇦Canada erichomanchuk

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

Merge Requests

Comments & Activities

Production build 0.71.5 2024