Is there a way to make my template more aware of the regions being passed in?

For example. If the layout variables would be in a array, i could loop trough them. Is there something i could do to make this happen?

CommentFileSizeAuthor
#14 layout_render_info.patch2 KBaspilicious
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

aspilicious’s picture

Version: 7.x-2.4 » 8.x-2.x-dev
Category: support » feature
Issue tags: +theming

Not for D7 I'm afraid. Maybe you can convince me for D8.
I'm not convinced yet as core templates behave the same as ds.

Jeff Burnz’s picture

Issue summary: View changes

I'm keen on this also, I have done this in my starter theme for the page template (print quite advanced set of layout classes), so I am pretty interested in looking into this for DS, either by default or some way of making this happen in my theme.

jstoller’s picture

If I understand this issue correctly, I'm having the same problem in a D7 site. I've been pounding my head against a wall trying to figure out how to set a class on the body element, or on something in the page template, based on what DS regions have content in them. Any help in this regard would be greatly appreciated.

jstoller’s picture

While I still think this is an important feature and would like to see it added to DS, I did find a workaround using the Context module. In a companion module I created for my theme I implement hook_ds_pre_render_alter():

/**
 * Implements hook_ds_pre_render_alter().
 */
function csctheme_ds_pre_render_alter(&$layout_render_array, $context) {
  if($context['entity_type'] == 'node' && $context['view_mode'] == 'full') {
    // Set a context indicating the presence of an info box region in this node.
    $has_info_box = (isset($layout_render_array['info_box']) && count($layout_render_array['info_box']) > 0) ? TRUE : FALSE;
    context_set('csc', 'has_info_box', $has_info_box);
    // Set a context indicating the presence of an aside region in this node.
    $has_aside = (isset($layout_render_array['sidebar']) && count($layout_render_array['sidebar']) > 0) ? TRUE : FALSE;
    context_set('csc', 'has_aside', $has_aside);
  }
}

This sets two site-wide contexts indicating the presence of content in two of my standard DS layout regions. Now I can check for those contexts in my theme's template.php file and add the appropriate classes to the body element.

/**
 * Implements hook_preprocess_html()
 */
function labrat_preprocess_html(&$vars) {
  // Add classes indicating the presence of an info box or aside in the article.
  $vars['classes_array'][] = context_get('csc', 'has_info_box') ? "has-info-box" : "no-info-box";
  $vars['classes_array'][] = context_get('csc', 'has_aside') ? "has-aside" : "no-aside";
}
aspilicious’s picture

Stil nog convinced, You van have 10 ds layouts on 1 page, how can I know what layout is important for you?

Or am I overcomplicating things?

jstoller’s picture

@aspilicious, I think you may be over complicating things. :-)

The basic idea is that DS needs to pass a little information about what it's doing up the food chain, so the templates displaying the content DS renders can understand what they're displaying. If you take the page template (and HTML, by extension), it has one $content variable, displaying one entity, which has been rendered using a single DS layout. That is the "important" layout.

The DS layout I use to render my page content has seven different regions, but they don't all contain content on every node. My page and HTML templates needs to know which of the regions in that DS layout are actually being rendered with any content, so they can make small adjustments in response. Adding a class on the body element, for instance, if there happens to be content in a node's $sidebar region. I don't believe this is an edge case.

I think the problem could be solved if DS simply added a little information to an entity object when rendering that entity. At a minimum, I would expect each entity to know what DS layout was used to render it, what regions were defined in that layout, and which of those regions actually contain content for the current entity. Providing additional information about the nature of the content in each region would be an added bonus. All of this information is freely available when DS renders an entity. DS just needs to pass it on, so other functions can access it.

aspilicious’s picture

At a minimum, I would expect each entity to know what DS layout was used to render it,

Ok so let's say you render node/5 in the content region with layout X and you render node/5 again in the sidebar with layout Y. Which layout should be attached to the entity?

Per definition it's incorrect to attach a layout onto an entity object as they are not tightly coupled. Each entity can be attached to several layouts.

jstoller’s picture

Ahh. I suppose I hadn't considered the same node being rendered in different ways on the same page. Still, there is only one DS layout per view mode, per entity, so perhaps that is the key. I'm just thinking aloud, but what if you added an $entity->ds_layouts array to each entity and anytime DS renders an entity it just adds another element to the array, keyed by the view mode it is rendering. If the page content is the only place that node/5 has been rendered then there will only be one element in the ds_layouts array. If it also appears in the sidebar then there will be two elements, but for any given template I'll always know which view mode I'm looking at, so I can always get to the appropriate information. In my page template, I know I can just look in $node->ds_layouts['full'] to see what's been rendered. Meanwhile, in my block template I could look at $node->ds_layouts['block'], and in my views template I could look at $node->ds_layouts['teaser'].

aspilicious’s picture

Maybe I still don't get it but why aren't you just calling these functions than?

/**
 * Get a layout for a given entity.
 *
 * @param $entity_type
 *   The name of the entity.
 * @param $bundle
 *   The name of the bundle.
 * @param $view_mode
 *   The name of the view mode.
 * @param $fallback
 *   Whether to fallback to default or not.
 *
 * @return $layout
 *   Array of layout variables for the regions.
 */
function ds_get_layout($entity_type, $bundle, $view_mode) {
}

and

/**
 * Get the field settings.
 *
 * @param $entity_type
 *   The name of the entity.
 * @param $bundle
 *   The name of bundle (ie, page or story for node types, profile for users)
 * @param $view_mode
 *   The name of view mode.
 */
function ds_get_field_settings($entity_type, $bundle, $view_mode) {
}

Btw, the content of these functions are statically cached. So super fast when using in your template code.
So the only thing you're missing is a list of regions that are used. Correct?

Btw the $context params in hook_ds_render_alter() contains an entity object. I'm not sure but can't you alter it inside the later hook your self?
$entity = $context['entity'];

I actually like your work around and it still feels very dirty to me to populate the entity object with extra information.

jstoller’s picture

Display Suite takes on such a big role when rendering a page at this point that I would hardly qualify it as "extra information." DS regions are major structural elements on the page. In my site the page title, local actions, and Drupal messages are all rendered through Display Suite, in addition to multiple distinct content regions. What DS regions are rendered, and with what content, is integral to an entity, yet Display Suite does everything in a black box. An entity goes in and markup comes out, but what went into that markup is hidden from view. In my mind, that is a huge problem. I'm a little shocked that there haven't been more people clamoring to get at this data.

aspilicious’s picture

Assigned: Unassigned » swentel

To be honest I have never needed this data, same for my colleagues. And I'm working full time with Drupal for the last 3 years. And there are only two people in this thread :D

Hmm I need a second opinion from Swentel. You could also use "drupal_static" instead of "context_set" int hat pre render function.

jstoller’s picture

Actually, there are four people on this thread. The others just aren't as loud as me. :-)

Perhaps I'm just pushing things in my theme more than most, but this is not the first time I've needed to know what DS was doing and couldn't get at the information. It should not be surprising that in a complex responsive layout, one part of a page might need to know what's happening on another part of the page. It can be hard to deal with things like off-canvas sidebars if the page doesn't know whether the sidebar even exists.

Jeff Burnz’s picture

Actually there are three people in this thread :) I'm looking for a way to control the layout, so if a region is not used I can tweak the layout to account for that. DS doesn't need to print anything by default, but I need the data to do this. Like jstoller I would really, really like to be able to do this.

aspilicious’s picture

Status: Active » Needs review
FileSize
2 KB

So this patch could make you guys happy?

swentel’s picture

I understand the use case exposing the regions in the template, I've actually considered adding it at one point, but in the end we never needed it in our projects.

Dynamically adding properties to the entity object is a bit dirty, and also annoying when you have entity cache enabled in D7 because you'll probably end up with stale data that shouldn't be cached anyway. And in D8, entity caching is on default, so even more annoying - unless there's a way to tell entity cache to ignore properties, but I'm not sure whether that's even possible at all.

So, I'd say, knowing the layout info/regions in template, sure, why not. Dynamic properties, maybe in another patch so we can test the behavior with entity caching properly?

aspilicious’s picture

But without the dynamic aspect you can just call the functions in #9.
Yes I was also worried about entity caching...

swentel’s picture

Status: Needs review » Closed (outdated)

Looks like this outdated completely.