To open, very familiar with Drupal 8 Naming Conventions .
In regards to the blocks section, it covers extending blocks via modules. I understand this very well.

At risk of butchering terminology:
Is it possible to extend D8's custom block types without using a module?
For example:
When we theme a custom content type in D8, we would use: node--custom_content_type.html.twig
To further this: printing an image field from the content type, we would use:

{{ content.field_name }}

{# /* Would we follow the same method content.field_name for printing fields from blocks? */ #}
  1. Are we capable of approaching Custom Block Types in the same manner as Content Types?
  2. Do we follow the same naming convention such as block--custom_block_type.html.twig?
  3. If this is possible, is it necessary to add theme hook in mytheme.theme so drupal recognizes the template ? I ask this as we've noticed its not necessary with content types.

Any thoughts are greatly appreciated!

Comments

alarez’s picture

Hello,

I'm trying to implement exactly what you explained without any luck.
Same as you" very familiar with Drupal 8 Naming Conventions".
Unfortunately the article doesn't cover the naming conventions for custom block types as it does for custom content types.

I will really appreciate any advice.

Thanks.

TheThemerist’s picture

Sorry I can't help.
Searching for the same answer on my first D8 build.
Love that Beans have 'been' ported to core in the form of custom block types, but wish the was a way to easily target them for theming.
Even a class of 'this-block-style' printed to the block class array would be a massive help.
Of course the perfect solution would indeed be a recognised template naming convention for custom block types.

Jeff Burnz’s picture

I dont know what beans is but you can add a suggestion for a custom block bundle/type by using hook_theme_suggestions_HOOK_alter() in MYTHEME.theme file and clear the cache:

/**
 * Implements hook_theme_suggestions_HOOK_alter() for form templates.
 * @param array $suggestions
 * @param array $variables
 */
function HOOK_theme_suggestions_block_alter(array &$suggestions, array $variables) {
  if (isset($variables['elements']['content']['#block_content'])) {
    array_splice($suggestions, 1, 0, 'block__bundle__' . $variables['elements']['content']['#block_content']->bundle());
  }
}

My custom type/bundle is called "Links" and the block instance is titled "Crazy Links".

If you are in twig debug mode you should see something this in the inspector:

<!-- FILE NAME SUGGESTIONS:
   * block--crazylinks.html.twig
   * block--block-content--bcf3d06c-c4b4-47b8-a404-4d8791706aba.html.twig
   x block--bundle--links.html.twig
   * block--block-content.html.twig
   * block.html.twig
-->

You can see the suggestion block--bundle--links.html.twig is being used, becaus I have created the file and cleared the cache.

I can customise the output, e.g. just print the URL from my link field, and set a class using the bundle name (this will be "bundle-links"), note I have had to use a known field to get the bundle, there may be a better way but this was quick and dirty debugging to get this far and it works.

{%
  set classes = [
    'block',
    'block-' ~ configuration.provider|clean_class,
    'block-' ~ plugin_id|clean_class,
    label ? 'has-title',
    content['body']['#bundle'] ? 'bundle-' ~ content['body']['#bundle'],
  ]
%}
<div{{ attributes.addClass(classes) }}>
  <div class="block__inner">

    {{ title_prefix }}
    {% if label %}
      <h2{{ title_attributes.addClass('block__title') }}><span>{{ label }}</span></h2>
    {% endif %}
    {{ title_suffix }}

    {% block content %}
      <div{{ content_attributes.addClass('block__content') }}>
        {{ content.field_ext_lnk[0]['#url'] }}
      </div>
    {% endblock %}

  </div>
</div>
TheThemerist’s picture

Thanks Jeff!
That works an absolute treat.
Exactly what i was after.

PS ''bean' was a D7 module which allowed you to create 'beans', which like content types could contain custom fields etc.
https://www.drupal.org/project/bean
The module was ported into D8 core as 'custom block types'

Anonymous’s picture

works!!!

scm6079’s picture

Thank you, this worked perfectly.

nikolay shapovalov’s picture

For Drupal 8.2

use Drupal\Component\Utility\Html;

/**
 * Implements template_preprocess_block().
 */
function THEME_preprocess_block(&$vars) {
  if (!empty($vars['content']['#block_content'])) {
    $block_bundle = $vars['content']['#block_content']->bundle();
    $vars['attributes']['class'][] =  'block--block-content--' . Html::cleanCssIdentifier($block_bundle);
  }
}

/**
 * Implements hook_theme_suggestions_block_alter().
 */
function THEME_theme_suggestions_block_alter(array &$suggestions, array $variables, $hook) {
  $element = $variables['elements'];
  if (!empty($element['content']['#block_content'])) {
    $block_bundle = $element['content']['#block_content']->bundle();
    $suggestions_name = 'block__block_content__' . $block_bundle;
    // Put it after 2 items from behind.
    array_splice($suggestions, -2, 0, $suggestions_name);
  }
}
<!-- FILE NAME SUGGESTIONS:
   * block--block-name.html.twig
   * block--block-content--b436f9c6-34ae-4879-8b55-068015a999d3.html.twig
   * block--block-content--bundle-name.html.twig
   * block--block-content.html.twig
   * block--block-content.html.twig
   x block.html.twig
-->

Are you looking for developer? I am looking for a new team.

nerdstein’s picture

Jeff Burnz’s picture

Extra check with BlockContentInterface, nice one, this is what people should use.

academiaingles’s picture

Thanks for the information, It's just what I was looking for

leisurman’s picture

I was looking to do the same thinf. I used _preprocess_block. I found the answer here:
https://drupal.stackexchange.com/questions/252201/access-node-from-a-block