Skip to content

Instantly share code, notes, and snippets.

@TerranRich
Forked from cesarmiquel/drupal-8-cheatsheet.md
Last active March 19, 2024 16:48
Show Gist options
  • Save TerranRich/d84b18879ce60750197d26ac08d478af to your computer and use it in GitHub Desktop.
Save TerranRich/d84b18879ce60750197d26ac08d478af to your computer and use it in GitHub Desktop.
Drupal 10 Cheat Sheet

Drupal 10 Cheat Sheet

This was forked from cesarmiquel/drupal-8-cheatsheet.md and udpated to adhere to D10 standards. This is still a work in progress.

Files, Images and Media

Basics:

use Drupal\file\Entity\File;

// Load file object.
$file = File::load($file_id);

// Get URI (public://foo/bar/baz.png).
$file_uri = $file->getFileUri();

// Absolute path in file system (/var/www/drupal/sites/default/files/foo.txt).
$path_abs = \Drupal::service('file_system')->realpath($uri);

// Relative path in file system (/sites/default/files/... if public://).
$path_rel = \Drupal::service('file_url_generator')->generateString($uri);

// Load file contents.
$contents = file_get_contents($uri);

Create a directory in public:// if it doesn't exist:

$image_dest = 'public://article/images';                                                           
if (!is_dir($image_dest)) {                                                                      
  \Drupal::service('file_system')->mkdir($image_dest, NULL, TRUE);                               
}   

Create a file using FileRepository::writeData (docs) in Drupal from image data:

use Drupal\Core\File\FileSystemInterface;

$image_url = "https://example.com/images/img.png";
$image_content = file_get_contents($image_url);                                                            
$image_filename = "img.png";

if ($image_content) {
  $image_fid = \Drupal::service('file.repository')
    ->writeData(
      $image_content,
      "$image_dest/$image_filename",
      FileSystemInterface::EXISTS_REPLACE
    );
}

Once we have a FileEntity (returned by writeData) you can create a Media entity like so:

$data = [
  'bundle' => 'image',
  'name' => 'Title/ALT text form image',
  'field_media_image' => ['target_id' => $imageFid],
];

$mediaEntity = \Drupal::entityManager()
  ->getStorage('media')
  ->create($data);
$mediaEntity->save();

Nodes

use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;

// Load a node.
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);

// Load a taxonmomy term.
$term = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->load($tid);

$item = [
  'nid'          => $nid,
  'title_prefix' => $node->field_supplement_title_prefix->value,
  'title'        => $node->title->value,
  'tid'          => $tid,
  'supplement'   => $term->getName(),
  'home_image'   => $this->getImagesCrop(...),
  'cover_image'  => $this->getImagesCrop(...),
  'slug'         => $term->field_slug->value,
  'date'         => $node->field_supplement_date->value,
];

// Body text.
$body_text = $node->body->value;
$body_text = $node->get('body')->value;
$body_array = $node->body->getValue();
/**
 * $body_text  example: '<p>Hello!</p>'
 * $body_array example: [
 *   0 => [
 *     'value'   => '<p>Hello!</p>',
 *     'summary' => '',
 *     'format'  => 'basic_html',
 *   ],
 * ]
 */

// Other alternatives.
$field_value = $node->get('field_slug')->getString();
$field_value = $node->field_slug->getString();

// Make changes and preserve them:
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
$prev_changed = $node->getChangedTime();
$node->title = "New Title";
...
$node->save()

// You need to reload and only modify changed for this to work!!
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
$node->setChangedTime($prev_changed);
$node->save();

Get the path of a node with:

$alias = \Drupal::service('path_alias.manager')->getAliasByPath("/node/$nid");

If you have a node object you can use:

// Absolute URL.
$url_abs = $node->toUrl()->setAbsolute()->toString();

// Relative URL.
$url_rel = $node->toUrl()->toString();

To search nodes by properties:

$nodes = \Drupal::entityTypeManager()
  ->getStorage('node')
  ->loadByProperties([
    'type'  => 'article',
    'title' => 'Some title',
  ]);

Access entity reference fields

In this sample code, article is a content type with a field_author field that is an entity reference to another content type called author:

if ($article->field_author->isEmpty()) {
  // Doesn't have an author.
  return;
}

$article_authors = [];
foreach ($article->field_author as $author) {
  $author_node = $author
    ->get('entity')
    ->getTarget()
    ->getValue();
  $article_authors[] = [
    'id'               => $author_node->id(),
    'title'            => $author_node->title->value,
    'field_first_name' => $author_node->field_first_name->value,
    'field_last_name'  => $author_node->field_last_name->value,
    'field_slug'       => $author_node->field_slug->value,
  ];
}

...or, better yet:

$authors = $article->get('field_author')->referencedEntities();
foreach ($authors as $author) {
  $article_authors[] = [
    'id' => $author->id(),
    // ...
  ];
}

Creating nodes

// Assuming the image is already uploaded to your server:
$fid = '123'; // The fid of the image you are going to use.
$image_media = Media::create([
  'bundle' => 'your_image_bundle_name_here',
  'uid' => '1',
  'langcode' => Language::LANGCODE_DEFAULT,
  'status' => Media::PUBLISHED,
  'your_image_field_name_here' => [
    'target_id' => $fid,
    'alt'       => t('foo'),
    'title'     => t('bar'),
  ],
]);
$image_media->save();

// Then do the same for the video media entity.
// $video_media = ... ->save();

$node = Node::create([
  // The node entity bundle.
  'type'     => 'article',
  'langcode' => 'en',
  'created'  => $created_date,
  'changed'  => $created_date,
  // The user ID.
  'uid' => 1,
  'moderation_state' => 'published',
  'title' => $title,
  'field_article_section' => ['target_id' => $section_target_id],
  'field_author' => 111,
  'field_article_main_image' => ['target_id' => $image_media->id()],
  'field_article_main_video' => [
     // ... the same as before
  ],
  'field_article_body_summary' => [
    'summary' => substr(strip_tags($text), 0, 100),
    'value'   => $text,
    'format'  => 'rich_text',
  ]
]);
$node->save();
$new_nid = $node->id();

References:

Image styles

Get the image style from a file or a uri. Taken from this gist:

use Drupal\file\Entity\File;
use Drupal\image\Entity\ImageStyle;

// File ID.
$fid = 123;

// Load file.
$file = File::load($fid);

// Get origin image URI.
$image_uri = $file->getFileUri();

// Load image style "thumbnail".
$style = ImageStyle::load('thumbnail');

// Get URI.
$uri = $style->buildUri($image_uri);

// Get URL.
$url = $style->buildUrl($image_uri);

Taxonomy

// Load taxonomy tree.
$tree = \Drupal::entityTypeManager()
  ->getStorage('taxonomy_term')
  ->loadTree(self::HOME_SUPPLEMENT_LIST_VID);

Entity queries

// Sample query on nodes:
$query = \Drupal::entityQuery('node');
$query->condition('status', 1);
$query->condition('type', 'supplement');
$query->condition('field_supplement_type.entity.tid', $slug->tid);
// ...or by name:
$query->condition('field_tags.entity.name', 'tag1');
// ...or by parent tid:
$query->condition('field_supplement_type.entity.parent', $slug->tid);
// Disable access control if we are anonynous, for example.
$query->accessCheck(FALSE);
 
$now = new DrupalDateTime('now');
// Set a desired timezone (instead of the site/server default):
$now->setTimezone( new \DateTimeZone(DATETIME_STORAGE_TIMEZONE) );
$query->condition('field_date', $now->format(DATETIME_DATETIME_STORAGE_FORMAT), '>=');

$query->sort('field_supplement_date', 'DESC');
$query->range(0, 1);
$entity_ids = $query->execute();

foreach ($entity_ids as $nid) {
  // Load all information for this node.
  $node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
  // Do something with node and return some data
  $supplements[] = $doSomething($node);
}
 
// Sample query on taxonomy. Filtering by a custom column on a taxonomy
$query = \Drupal::entityQuery('taxonomy_term');
$query->condition('vid', 'vocubulary_name');
$query->condition('field_custom_text', $text);
$tids = $query->execute();
$terms = \Drupal\taxonomy\Entity\Term::loadMultiple($tids);

References:

Services

Using services:

$service = \Drupal::service('module.service_name');

$result = $service->methodInMyService(...);

Creating a service

Example taken from https://www.drupal.org/project/drupal/issues/2945539#comment-13291384).

Add a mymodule.services.yml to your module directory:

services:
  mymodule.myservice:
    class: Drupal\mymodule\Services\MyService
    arguments: ['@entity_type.manager']

Add the service in src/Services/MyService.php with:

namespace Drupal\mymodule\Services;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeStorageInterface;

/**
 * Class MyService.
 */
class MyService {

  /**
   * @var EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * @var NodeStorageInterface
   */
  protected $nodeStorage;

  /**
   * @param EntityTypeManagerInterface $entity_type_manager
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
    $this->nodeStorage =  $this->entityTypeManager->getStorage('node');
  }

  /**
   * Load a node.
   *
   * @param int $nid ID of the node to load.
   */
  public function loadANode($nid) {
    return $this->nodeStorage->load($nid);
  }
}

Dependencies

It is good practice to pass along references to popular services instead of using \Drupal::service(). For example: if you need an entityTypeManager it is preferred to inject it instead of using \Drupal::entityTypeManager(). It makes your code more easily testable. Some common services to inject into your Service might be:

  • entity_type.manager - EntityTypeManager object to perform entity queries on
  • database - Connection object to the Drupal database to perform queries on
  • current_user - AccountProxy to the current user
  • date.formatter - DateFormatter object which gives you access to the DateFormat::format() using Drupal date formats

Additional resources:

Config

To use your config:

$config = \Drupal::service('config.factory')->get('mymodule.settings');
$value = $config->get('key');
...

...or, more simply:

$config = \Drupal::config('mymodule.settings')->get('name_of_form_field');

To write to your config:

// Get the site name (with overrides, same as before).
$site_name = \Drupal::config('system.site')->get('name');

// Set the site name.
\Drupal::configFactory()
  ->getEditable('system.site')
  ->set('name', 'My fantastic site')
  ->save();

Migrating variable_get()/variable_set() (D7→8)

In Drupal 7 it was easy to save state information of your module in variables using variable_get() / variable_set() API. As of Drupal 8 you now must use the config.factory service to store and retrieve values:

// Equivalent to `variable_set('my_module_varname', $value)`:
$config = \Drupal::service('config.factory')
  ->getEditable('my_module.settings');
$config->set('varname', $value);
$config->save();
// Equivealent to `$value = variable_get('my_module_varname')`:
$config = \Drupal::service('config.factory')
  ->getEditable('my_module.settings');
$value = $config->get('varname');

References:

Custom entities

baseFieldDefinitions

Let's take a look at the method baseFieldDefinitions and its abilities.

Base fields are non-configurable fields that always exist on a given entity type, like the node title or created and changed dates. By definition, base fields are fields that exist for every bundle.

Entity types define their base fields in a static method baseFieldDefinitions on the entity class. The definitions returned by this function can be overridden for all bundles by hook_entity_base_field_info_alter() or on a per-bundle basis via base_field_override configuration entities.

Drupal core has the following base field types:

  • boolean
  • changed
  • created
  • decimal
  • email
  • entity_reference
  • float
  • integer
  • language
  • map
  • password
  • string
  • string_long
  • timestamp
  • uri
  • uuid
  • comment
  • datetime
  • file
  • image
  • link
  • list_float
  • list_integer
  • list_string
  • path
  • telephone
  • text
  • text_long
  • text_with_summary

Below you can find examples of most of these types of fields.

entity_reference field

$fields['user_id'] is an example of an entity_reference field.

The default widget is entity_reference_autocomplete, while the default formatter is entity_reference_label. In settings, you can set the entity type for autocomplete. Also, you can set a handler (see Change Entity Autocomplete Selection Rules in Drupal 8 for examples of how to create custom handlers).

With the setDisplayOptions config, we can set options for the field widget (display context: form) and the field formatter (display context: view).

For a better understanding, here is another example using a node entity:

$fields['article'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel( t('Article') )
  ->setDescription( t('Article description.') )
  ->setSetting('target_type', 'node')
  ->setSetting('handler', 'default:node')
  ->setSetting('handler_settings', [
    'target_bundles' => [
      'article' => 'article',
    ],
    'auto_create' => FALSE,
  ])
  ->setRequired(TRUE)
  ->setTranslatable(FALSE)
  ->setDisplayOptions('view', [
    'label'  => 'visible',
    'type'   => 'string',
    'weight' => 2,
  ])
  ->setDisplayOptions('form', [
    'type'     => 'entity_reference_autocomplete',
    'weight'   => 2,
    'settings' => [
      'match_operator' => 'CONTAINS',
      'size' => '60',
      'placeholder' => 'Enter article title here...',
    ],
  ])
  ->setDisplayConfigurable('view', TRUE)
  ->setDisplayConfigurable('form', TRUE);

Note that we can set target_bundles in handler_settings.

String field

$fields['name'] is an example of a string field.

This field contains a plain string value. The default widget is string_textfield, and the default formatter is string.

string_long field

We can also create a string_long field that can contain a long string value. The default widget is string_textarea, and the default formatter is basic_string.

$fields['notes'] = BaseFieldDefinition::create('string_long')
  ->setLabel( t('Notes') )
  ->setDescription( t('Example of a string_long field.') )
  ->setDefaultValue('')
  ->setRequired(FALSE)
  ->setDisplayOptions('view', [
    'label'  => 'visible',
    'type'   => 'basic_string',
    'weight' => 5,
  ])
  ->setDisplayOptions('form', [
    'type'     => 'string_textarea',
    'weight'   => 5,
    'settings' => [
      'rows' => 4,
    ],
  ])
  ->setDisplayConfigurable('view', TRUE)
  ->setDisplayConfigurable('form', TRUE);

boolean field

If an entity field contains a boolean value, the default widget is boolean_checkbox and the default formatter is boolean.

$fields['status'] = BaseFieldDefinition::create('boolean')
  ->setLabel(t('Publishing status'))
  ->setDescription(t('A boolean indicating whether the Demo entity is published.'))
  ->setDefaultValue(TRUE)
  ->setSettings([
    'on_label'  => 'Published',
    'off_label' => 'Unpublished'
  ])
  ->setDisplayOptions('view', [
    'label'  => 'visible',
    'type'   => 'boolean',
    'weight' => 2,
  ])
  ->setDisplayOptions('form', [
    'type'   => 'boolean_checkbox',
    'weight' => 2,
  ])
  ->setDisplayConfigurable('view', TRUE)
  ->setDisplayConfigurable('form', TRUE);

list_integer, list_float, and list_string fields

These fields come from the options module and are more or less similar to one another, so it should be sufficient to demonstrate the use of one of them.

All of these fields have options_select as the default widget and list_default as the default formatter.

$fields['http_status'] = BaseFieldDefinition::create('list_integer')
  ->setLabel( t('HTTP status code') )
  ->setDescription( t('Hypertext Transfer Protocol (HTTP) response status codes.') )
  ->setDefaultValue(200)
  ->setSettings([
    'allowed_values' => [
      200 => 'OK',
      201 => 'Created',
      202 => 'Accepted',
      300 => 'Multiple Choices',
      301 => 'Moved Permanently',
      302 => 'Moved Temporarily',
      403 => 'Forbidden',
      404 => 'Not Found',
    ],
  ])
  ->setDisplayOptions('view', [
    'label'  => 'visible',
    'type'   => 'list_default',
    'weight' => 6,
  ])
  ->setDisplayOptions('form', [
    'type'   => 'options_select',
    'weight' => 6,
  ])
  ->setDisplayConfigurable('view', TRUE)
  ->setDisplayConfigurable('form', TRUE);

text, text_long, and text_with_summary fields

These fields store a text and a text format.

As the default is formatted, all of them use text_default. The widgets for each field, respectively, are text_textfield, text_textarea and text_textarea_with_summary.

$fields['text_long'] = BaseFieldDefinition::create('text_long')
  ->setLabel( t('Text (formatted, long)') )
  ->setDescription( t('Formatted text, long.') )
  ->setDisplayOptions('view', [
    'label'  => 'visible',
    'type'   => 'text_default',
    'weight' => 6,
  ])
  ->setDisplayOptions('form', [
    'type'   => 'text_textarea',
    'weight' => 6,
    'rows'   => 6,
  ])
  ->setDisplayConfigurable('view', TRUE)
  ->setDisplayConfigurable('form', TRUE);

datetime field

$fields['start_date'] = BaseFieldDefinition::create('datetime')
  ->setLabel( t('Only Date') )
  ->setDescription( t('Date field example.') )
  ->setRevisionable(TRUE)
  ->setSettings([
    'datetime_type' => 'date',
  ])
  ->setDefaultValue('')
  ->setDisplayOptions('view', [
    'label'    => 'above',
    'type'     => 'datetime_default',
    'settings' => [
      'format_type' => 'medium',
    ],
    'weight' => -9,
  ])
  ->setDisplayOptions('form', [
    'type'   => 'datetime_default',
    'weight' => -9,
  ])
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayConfigurable('view', TRUE);

Widgets

Plugin ID Plugin class
boolean_checkbox Drupal\Core\Field\Plugin\Field\FieldWidget\BooleanCheckboxWidget
datetime_datelist Drupal\datetime\Plugin\Field\FieldWidget\DateTimeDatelistWidget
datetime_default Drupal\datetime\Plugin\Field\FieldWidget\DateTimeDefaultWidget
datetime_timestamp Drupal\Core\Datetime\Plugin\Field\FieldWidget\TimestampDatetimeWidget
email_default Drupal\Core\Field\Plugin\Field\FieldWidget\EmailDefaultWidget
entity_reference_autocomplete Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget
entity_reference_autocomplete_tags Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteTagsWidget
field_example_3text Drupal\field_example\Plugin\Field\FieldWidget\Text3Widget
field_example_colorpicker Drupal\field_example\Plugin\Field\FieldWidget\ColorPickerWidget
field_example_text Drupal\field_example\Plugin\Field\FieldWidget\TextWidget
field_permission_example_widget Drupal\field_permission_example\Plugin\Field\FieldWidget\TextWidget
file_generic Drupal\file\Plugin\Field\FieldWidget\FileWidget
image_image Drupal\image\Plugin\Field\FieldWidget\ImageWidget
language_select Drupal\Core\Field\Plugin\Field\FieldWidget\LanguageSelectWidget
link_default Drupal\link\Plugin\Field\FieldWidget\LinkWidget
menu_item_extras_view_mode_selector_select Drupal\menu_item_extras\Plugin\Field\FieldWidget\MenuItemExtrasViewModeSelectorSelect
moderation_state_default Drupal\content_moderation\Plugin\Field\FieldWidget\ModerationStateWidget
number Drupal\Core\Field\Plugin\Field\FieldWidget\NumberWidget
oembed_textfield Drupal\media\Plugin\Field\FieldWidget\OEmbedWidget
options_buttons Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsButtonsWidget
options_select Drupal\Core\Field\Plugin\Field\FieldWidget\OptionsSelectWidget
path Drupal\path\Plugin\Field\FieldWidget\PathWidget
string_textarea Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextareaWidget
string_textfield Drupal\Core\Field\Plugin\Field\FieldWidget\StringTextfieldWidget
text_textarea Drupal\text\Plugin\Field\FieldWidget\TextareaWidget
text_textarea_with_summary Drupal\text\Plugin\Field\FieldWidget\TextareaWithSummaryWidget
text_textfield Drupal\text\Plugin\Field\FieldWidget\TextfieldWidget
uri Drupal\Core\Field\Plugin\Field\FieldWidget\UriWidget

References:

Logging

Instead of using watchdog() we now use Drupal's logger:

\Drupal::logger('my_module')->error($message);

Other options:

\Drupal::logger('my_module')->emergency($message, $vars);
\Drupal::logger('my_module')->alert($message, $vars);
\Drupal::logger('my_module')->critical($message, $vars);
\Drupal::logger('my_module')->error($message, $vars);
\Drupal::logger('my_module')->warning($message, $vars);
\Drupal::logger('my_module')->notice($message, $vars);
\Drupal::logger('my_module')->info($message, $vars);
\Drupal::logger('my_module')->debug($message, $vars);

Other resources:

Normalizer and Serializer

Links:

Creating your own Normalizer

Create a class in my_module/src/Normalizer/MyEntityNormalizer.php with the normalizer code:

namespace Drupal\my_module\Normalizer;

use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;

class MyEntityNormalizer extends SerializerAwareNormalizer implements NormalizerInterface {

  public function normalize($entity, $format = NULL, array $context = []) {
    $normalizer['id'] = $entity->id();
    $normalizer['field_title'] = $entity->field_title->value;
    
    // Calling normalizer on referenced entities:
    $normalized['field_xxxxxx'] = array_map(function($district) use ($format, $context) {
      return $this->serializer->normalize($district, $format, $context);
    }, $entity->field_xxxxxx->referencedEntities());
    
    return $normalizer;
  }
  
  public function supportsNormalization($data, $format = NULL) {
    if (!is_object($data) || $format !== 'json') {
      return FALSE;
    }
    
    if ($data instanceof Entity) {
      return TRUE;
    }
    
    return FALSE;
  }
}

You must also add your Normalizer to my_module.services.yml:

services:
  my_module.entity_name.normalizer:
    class: Drupal\my_module\Normalizer\MyEntityNormalizer
    tags:
      - { name: normalizer, priority: 10 }

Using Serializer

use Drupal\node\Entity\Node;

// Serialize a node to JSON:
$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
$format = 'json';
$serialized_content = \Drupal::service('serializer')
  ->serialize($node, $format)
);

// Deserialize from JSON -> Node:
$node = \Drupal::service('serializer')
  ->deserialize($serialized_content, \Drupal\node\Entity\Node::class, 'json');

You can serialize more complex structures like so:

use Drupal\node\Entity\Node;

$list = [
 \Drupal::entityTypeManager()->getStorage('node')->load(44130),
 \Drupal::entityTypeManager()->getStorage('node')->load(44131),
 \Drupal::entityTypeManager()->getStorage('node')->load(44130),
];

$object = [
 'total' => 3,
 'data'  => $list,
];

print_r(
 \Drupal::service('serializer')->serialize($object, 'json')
);

The above will output:

{
  "data": [
    {
      "nid": "44130",
      "title": "First node title"
    },
    {
      "nid": "44131",
      "title": "Second node title"
    },
    {
      "nid": "44132",
      "title": "Third node title"
    }
  ],
  "total": 3
}

Migration

To run a migration via code:

// Run migration.
$manager = \Drupal::service('plugin.manager.migration');
$plugins = $manager->createInstances([]);
$migration = FALSE;
foreach ($plugins as $id => $plugin) {
  if ($id == '[[[migration-id]]]') {
    $migration = $plugin;
  }
}

// Implementation of MigrateMessageInterface to track migration messages.
$log = new MyLogMigrateMessage();

// If we're replacing, run with equivalent of drush `--update` flag
if ($replace) {
  $migration->getIdMap()->prepareUpdate();
}   

// Create MigrateExecutable instance.
$executable = new MigrateExecutable($migration, $log);

// Run migration.
$executable->import();

Storing temporary data

// Any unique namespace works, but it's best to use the same name as the module.
$tempstore = \Drupal::service('user.private_tempstore')->get('mymodule_name');
$tempstore->set('my_variable_name', $some_data);

// Retrieving data:
$tempstore = \Drupal::service('user.private_tempstore')->get('mymodule_name');
$some_data = $tempstore->get('my_variable_name');

// Clearing data:
$tempstore->set('my_variable_name', false);

Resources:

Rendering

To render a body field you can use check_markup():

$html = check_markup($text, $format_id, $lang);

$format_id can be basic_html, full_html, etc. The previous code is equivalent to:

$filter_types_to_skip = [...];
$build = [
  '#type'     => 'processed_text',
  '#text'     => $text,
  '#format'   => $format_id,
  '#filter_types_to_skip' => $filter_types_to_skip,
  '#langcode' => $langcode,
];
return \Drupal::service('renderer')
  ->renderPlain($build);

Caching

To clear the cache after the user changes some settings, you can clear the node_view cache tag with:

Drupal::entityManager()->getViewBuilder('node')->resetCache();

If you want to clear the cache of a specific tag, you can pass the node ID to to above method, or you can use:

\Drupal\Core\Cache\Cache::invalidateTags($node->getCacheTags());

Each node, block, etc. that is rendered has one or more cache tags (see the X-Drupal-Cache-Tags header of a page response), by invalidating them you can automatically clear all caches that contain them. You can enable debugging by setting http.response.debug_cacheability_headers: true in your services.yml file.

Resources:

Composer

Some useful composer commands:

$ composer show -a 'drupal/layout_paragraphs'

Info from https://repo.packagist.org: #StandWithUkraine
name     : drupal/layout_paragraphs
descrip. : Layout Paragraphs
keywords : Drupal
versions : 2.0.x-dev, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 2.0.0-beta9, 2.0.0-beta8, 2.0.0-beta7, 2.0.0-beta6, 2.0.0-beta5, 2.0.0-beta4, 2.0.0-beta3, 2.0.0-beta2, 2.0.0-beta1, 2.0.0-alpha4, 2.0.0-alpha3, 2.0.0-alpha2, 2.0.0-alpha1, 1.0.x-dev, 1.0.0, 1.0.0-beta5, 1.0.0-beta4, 1.0.0-beta3, 1.0.0-beta2, 1.0.0-beta1, dev-1.0.x, dev-2.0.x
type     : drupal-module
license  : GNU General Public License v2.0 or later (GPL-2.0+) (OSI approved) https://spdx.org/licenses/GPL-2.0+.html#licenseText
homepage : https://www.drupal.org/project/layout_paragraphs
source   : [git] https://git.drupalcode.org/project/layout_paragraphs.git 3dd79b5c389bc3dc638611dc245f3010b391c295
dist     : []
names    : drupal/layout_paragraphs

support
source : http://cgit.drupalcode.org/layout_paragraphs
issues : https://www.drupal.org/project/issues/layout_paragraphs

requires
drupal/core ^9.2 || ^10
drupal/paragraphs ^1.6

requires (dev)
drupal/paragraphs-paragraphs_library *
drupal/block_field ~1.0
drupal/entity_usage 2.x-dev

The above will show you the available versions and other information. The -a option shows uninstalled packages.

To install a specific version you can do:

$ composer require 'drupal/layout_paragraphs:2.0.0-beta9'

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment