Skip to content

Instantly share code, notes, and snippets.

@jennatollerson
Last active March 1, 2022 03:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jennatollerson/fcd5177476b6c7ab92ca1e3c1140be9c to your computer and use it in GitHub Desktop.
Save jennatollerson/fcd5177476b6c7ab92ca1e3c1140be9c to your computer and use it in GitHub Desktop.
Drupal Form API, add an image field that includes a preview and an alt text field to your custom module's configuration form.
<?php
// src/Form/SettingsForm.php
/* Include theses dependencies in my_custom_module.info.yml
dependencies:
- drupal:file
- drupal:image
*/
namespace Drupal\my_custom_module\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Security\TrustedCallbackInterface;
use Drupal\file\Element\ManagedFile;
use Drupal\file\Entity\File;
/**
* Configure My Custom Module's settings for this site.
*/
class SettingsForm extends ConfigFormBase implements TrustedCallbackInterface {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'my_custom_module_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['my_custom_module.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('my_custom_module.settings');
$form['general'] = [
'#type' => 'details',
'#title' => $this->t('Sitewide settings'),
'#collapsible' => TRUE,
'#open' => TRUE,
];
// Add a managed file form element for uploading an image.
$form['general']['my_custom_module_image'] = [
'#type' => 'managed_file',
'#title' => t('Image'),
'#description_display' => 'before',
'#upload_location' => 'public://',
'#upload_validators' => [
'file_validate_extensions' => ['gif png jpg jpeg'],
'file_validate_is_image' => [],
],
'#process' => ['::processImage'],
'#theme' => 'image_widget',
'#default_value' => $config->get('my_custom_module_image'),
];
$form['general']['my_custom_module_image']['alt'] = [
'#type' => 'textfield',
'#title' => t('Alternative text'),
'#maxlength' => 512,
// If we don't bust this element out of the tree, it doesn't appear at all
// in $form_state after submission. I cannot figure out why.
'#tree' => FALSE,
'#default_value' => $config->get('my_custom_module_image_alt'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// First, set image file to permanent so Drupal doesn't try to clean it up.
if (!empty($form_state->getValue('my_custom_module_image'))) {
$fid = reset($form_state->getValue('my_custom_module_image'));
$file = File::load($fid);
$file->setPermanent();
$file->save();
}
$this->config('my_custom_module.settings')
->set('my_custom_module_image', $form_state->getValue('my_custom_module_image'))
->set('my_custom_module_image_alt', $form_state->getValue('alt'))
->save();
parent::submitForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public static function trustedCallbacks() {
return [
'processImage',
'preRenderImage',
];
}
/**
* Tweak the Image field with a #process callback.
*/
public function processImage($element, &$form_state, $form) {
$element = ManagedFile::processManagedFile($element, $form_state, $form);
// If we remove the image, make sure the custom alt text goes away too.
if (empty($element['#value']['fids'])) {
$element['alt']['#default_value'] = NULL;
}
$element['#pre_render'][] = [SettingsForm::class, 'preRenderImage'];
return $element;
}
/**
* If an image is uploaded, show an image preview and an alt text field.
*/
public static function preRenderImage(array $element) {
// If a custom image's been uploaded.
if (!empty($element['#value']['fids'])) {
// There's only ever going to be one file here.
$fid = reset($element['#value']['fids']);
$file = File::load($fid);
$image = \Drupal::service('image.factory')->get($file->getFileUri());
// This will add preview of image at full size.
// If your image is not small you likely want to use
// '#theme' => 'image_style',
// '#style_name' => 'thumbnail', // choose an existing style.
$element['preview'] = [
'#theme' => 'image',
'#uri' => $image->getSource(),
'#alt' => $file->getFilename(),
'#height' => $image->getHeight(),
'#width' => $image->getWidth(),
];
}
else {
// If there's no file uploaded, hide the Alt text field.
$element['alt'] = [
'#access' => FALSE,
];
}
return $element;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment