Drupal 8 - Add machine name to block as class programmatically - drupal

I am looking for a way to add a class to a block, but not a custom class, a class from either the region name or the block machine name.
For example, with regions, this is possible:
{%
set classes = [ 'region-' ~ region|clean_class]
%}
And every divs would have the name of the region (defined in the info.yml file) as a class. I want to do the same thing with blocks. Either add the name of the region or the machine name as a class. The reason that I want a class is for CSS. It's better practice to target elements usings classes than IDs.
Does anyone know how to achieve that programmatically?

1) Twig on Drupal 8.x understands only variables and basic operations with variables. So in order to use custom variables (such as the block region) you need to pass the variables usually on a preprocess function and then use them inside Twig. Here is an example:
function MYTHEME_preprocess_block(&$variables, $hook) {
$block_id = $variables['elements']['#id'];
$block = \Drupal\block\Entity\Block::load($block_id);
// Add region as variable
$variables['region'] = $block->getRegion();
}
and then on block.html.twig file:
{%
set classes = ['region-'~region|clean_class]
%}
See the docs: https://www.drupal.org/docs/8/theming/twig/twig-best-practices-preprocess-functions-and-templates.
2) If you want to have custom block template suggestions (eg for a region) you can alter default theme suggestions using hook_theme_suggestions_alter().
function MYTHEME_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if ($variables['elements']['#configuration']['region']) {
$suggestions[] = 'block__' . $variables['elements']['#configuration']['region'];
}
}
3) Notice that you are not able to use region specific Drupal block twig templates by default because this functionality removed on 8.x. See related post: https://www.drupal.org/node/2011434.

The easiest way would be to use a contributed module such as block_class

I wanted this too and came across this SO post and OPs Drupal forum post of the same question while looking for an answer. Seeing as I think this answers what we were asking I thought I'd link it here for posterity.
From the Drupal forum comments use this snippet by Jeff Burnz in your block twig template:
{%
set classes = [
'block',
'block-' ~ attributes.id,
'block-' ~ plugin_id|clean_class,
label ? 'block-label-' ~ label|clean_class,
]
%}
<div{{ attributes.addClass(classes) }}>
This gives you a few options for classes, attributes.id is the one I wanted, and if you use just that it outputs
<div id="blockID" class="block-blockId"...
I hate styling by ids so will add this to all subthemes I work on from now on. Hope this helps.

Related

Shopware 6 custom product fields in tabs

I am completely new to the the Shopware (6) community and I am still learning how to code in Symfony and Vue.js.
After trying some how to's in the developer wiki, I wanted to try some coding by myself.
I would like to combine https://docs.shopware.com/en/shopware-platform-dev-en/how-to/add-admin-new-field and https://docs.shopware.com/en/shopware-platform-dev-en/how-to/new-tab-admin?category=shopware-platform-dev-en/how-to into one functionallity (Product tabs with custom admin fields).
However, when I use the v-model attribute into an input field, the complete tab will turn white and the following error is outputted in the console: product is not defined.
My guess is that the model needs to be imported into the module (I can't find this anywhere into the docs).
Can someone tell me what I have to do to make this work? My current source code can be found here: https://github.com/Millerdigital-matthew/miller-product-upsells
As I understand, you need to change your index.js as follows:
const { Component } = Shopware;
const { mapState } = Component.getComponentHelper();
Component.register('...', {
computed: {
...mapState('swProductDetail', [
'product'
]),
}
});
I looked into your current code.
In your extension you try to bind
v-model="product.manufacturerId"
But in the block you are extending, there is no product defined.
So the solution to this problem, is to define product on your
view/sw-product-detail-upsells

Drupal 8 list taxonomy terms

What is best way to retrieve Drupal 8 taxonomy terms and pass array to twig template?
Now I have:
In template.theme
function template_preprocess_page(&$variables) {
$variables['some_term'] = \Drupal::service('entity_type.manager')->getStorage("taxonomy_term")->loadTree('some_term', $parent = 0, $max_depth = NULL, $load_entities = FALSE);
}
Now in page.html.twig I can access {{ some_term }} array.
I feel that something is wrong about this. What is the best way to achieve this? I just need an array of selected taxonomy terms in page.html.twig. I want to use it to build custom HTML code.
Equivalent function in Wordpress is simple get_terms().
Your code seems to be OK.
Please check next:
Are you getting taxonomy tree array values in template_preprocess_page?
If not ($variables['some_term'] should not be empty array)
check if you are loading correct vocabulary with "...->loadTree('machine_name_of_vocabulary'..."
If yes check what twig is getting in page.html.twig You can check with: {{ dump(some_term) }}. Probably you will need to process array to get only for example list of term names.
Did you cleared Drupal cache?

Create html.twig in every pages in drupal 8

I'm newbie in drupal..
Here's the question, Is it possible to create html.twig in every pages?
Ex: aboutus.html.twig, contact.html.twig?
So that I can easily edit or adding content types for them..same as in default page.html.twig.
Looking at my twig debug information in the markup, it sure is possible what you are asking.
You can enable twig suggestions in development.services.yml with this lines:
parameters:
twig.config:
debug: true
While developing, you might also want to add:
cache: false
auto_reload: true
so you don't have to clear cache on every twig modification.
Anyway, after adding this and clearing caches, you will see that you can use something like html--front.html.twig or html--node--article.html.twig or any other combination usable with page.html.twig.
Take a look at this article to get the twig naming convention logic. There are at least three twig template types you have to know about: html.html.twig, page.html.twig and node.html.twig. They are nested.
Let's say your /aboutus page is /node/5
Use node--5.html.twig to alter it's layout.
if you want to overwrite a node your have to create a template.
there are two ways you can do this.
first:
create a node and overwrite it ( node--1.html.twig )
second: create a content-type and overwrite its template (more usefull in my opinion because you dont have a "static" node number.)
example:
name the content-type about-us. now you can write a template node--about-us.html.twig and use the field names u declaired: i.e. content.field_text1

Drupal Panel Pages Pathauto

I have a Panel Page set up with the path node/%node/foo and all works fine when I visit a link such as node/6/foo. However, when I visit nodealias/foo it doesn't work at all. Is it possible to get panels to work with pathauto in this way?
I am thinking I may have to implement the hook hook_url_inbound_alter and change the url myself.
I also posted a support request in the panels module here: http://drupal.org/node/1219796
As Alexey answers panels doesn't care about aliases, it only sees node/%nid
Here's a good explanation that is valid still for D7:
http://drupal.org/node/211338
To summarize and bring it up to date for D7:
Export your variant for the panel you've created and import it into the panel that overrides the default node display in Drupal.
Add Criterias to the variant so the Panel/variant is only used for the type(s) of content you want to display with this variant.
Voila :) (read the discussion at the link, else the summary will be difficult to understand)
Hope this helps - I myself have spend some time googling and trying to understand this, and I was also confused by the fact that Views DOES care about aliases...
I fixed this using the following code, you would need to alter the pattern to match the pattern of your url aliases and alter the function name to match your module's name.
function brooklands_url_inbound_alter(&$path, $original_path, $path_language) {
$pattern = '#^works\/[A-Za-z0-9]+(-[A-Za-z0-9]+)*\/images(\/\d+)?$#';
if(preg_match($pattern, $original_path)) {
$snip = substr($original_path, 0, strrpos($original_path, '/images'));
$system_path = drupal_lookup_path('source', $snip);
if($system_path) {
$tail = substr($original_path, strrpos($original_path, '/images'));
$path = $system_path . $tail;
}
}
}
You can use this module Subpathauto
it automatically makes the alias to work with subpaths, such as: nodealias/foo
The nodealias is the full alias of your node with nid=6. The third argument (foo) is added through hook_menu() by panels module to the exact alias (node/%nid/%anythingelse) and it is NOT applied to your aliased URL, so you can not use nodealias/foo url to access your panel just because it is not 'hooked' by panels module.
Changing url manually is a good idea, I think.

Drupal Taxonomy Block, Vocabulary Listing

I looking for the best way to implement a block that lists all terms of a certain vocabulary. Each term should link to page that lists all nodes associated with that term. Any help would be greatly appreciated. Thanks!
See here for a great tutorial to achieve exactly what you want
http://chrisshattuck.com/blog/how-add-block-menu-tags-or-other-taxonomy-terms-drupal-site
The easiest way to approach this would probably be to use Views, and simply create a new view of the type "term". Here's a quick example which assumes that you have some basic familiarity with the Views UI:
Visit Views > Add (build/views/add), give your new view a name, and select Term from the "View type" radio buttons.
On the next page, start by adding a Taxonomy: Vocabulary filter and selecting your vocabulary in the filter settings.
Add a Taxonomy: Term field and enable the Link this field to its taxonomy term page option in the field settings. You might also want to remove the field's label, since this is just a simple listing.
You probably want your display to display all terms in your vocabulary, so change the "Items to display" 0 (unlimited). By default, new views only display 10 items at a time.
Check out the Live preview below to see if it's outputting what you need.
Add a new Block display using the dropdown on the left side of the Views UI.
Give your new block a name in the "Block settings" area. This is the description that will appear on Drupal's block admin page.
Save your view and visit admin/build/block to place and configure your block.
It's worth noting that Views does indeed have some overhead, but in my experience, its flexibility and ease-of-use far outweigh the relatively minor performance hit.
If you'd like to avoid using Views, you could write a pretty simple custom module using hook_block() and adapting http://drupal.org/node/247472. If you'd like, I can edit this answer with an example module based on that.
(Posting this as another answer, since this is a different approach than my first answer.)
As I mentioned above, here's another approach involving a custom module based on the code at http://drupal.org/node/247472. You could also just drop that code into a custom block with the "PHP" input format selected, but that's generally considered to be bad practice.
Add a new folder in sites/all/modules called vocabulary_block. Customize and add the following two files:
vocabulary_block.module
<?php
/**
* #file
* Exposes a block with a simple list of terms from [vocabulary].
* Each term is linked to its respective term page.
*/
/**
* Lists terms for a specific vocabulary without descriptions.
* Each term links to the corresponding /taxonomy/term/tid listing page.
*/
function vocabulary_block_get_terms($vid) {
$items = array();
$terms = taxonomy_get_tree($vid, 0, -1, 1);
foreach($terms as $term) {
$items[]= l($term->name, "taxonomy/term/$term->tid");
}
if(count($items)) {
return theme('item_list', $items);
}
}
/**
* Implementation of hook_block().
*/
function vocabulary_block_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('List of [vocabulary] terms');
return $blocks;
case 'view':
if ($delta == 0) {
$vid = 43;
$block['subject'] = t('[Vocabulary]');
$block['content'] = vocabulary_block_get_terms($vid);
}
return $block;
}
}
vocabulary_block.info
name = Vocabulary Block
description = Exposes a block with a simple list of terms from [vocabulary]. Each term is linked to its respective term page.
; Core version (required)
core = 6.x
; Package name (see http://drupal.org/node/101009 for a list of names)
package = Taxonomy
; Module dependencies
dependencies[] = taxonomy
Notes
Be sure to change $vid = 43; to
reflect the ID of the vocabulary that
you'd like to load. You can find the
VID by visiting
admin/content/taxonomy and looking at
the destination of the edit
vocabulary link for your
vocabulary. The VID will be the last
fragment of that URL:
admin/content/taxonomy/edit/vocabulary/[vid].
I wouldn't normally hard-code the
$vid into the module itself. However,
setting up the necessary Drupal
variable and administration form (to
allow users to select a vocabulary
from the Drupal interface) would be
overkill for this answer.
For your own documentation purposes,
don't forget to search/replace
[vocabulary] in those two files and
use your own vocabulary's name
instead.
This method may not necessarily be more performant
than the Views method I described
earlier, especially once you start considering caching,
optimization, etc.
Since performance is a priority,
I recommend thoroughly testing a
variety of different methods on this page and
choosing whichever one is fastest for you.

Resources