Issue #2923701 by AdamPS, jonathanshaw, Pancho, Jo Fitzgerald, alexpott, Berdir, plach, larowlan, Samvel, lauriii, eelkeblok, imclean, oriol_e9g: Mechanism to disable preprocessing of node base fields so they can be configured via the field UI

8.7.x
Lee Rowlands 2019-02-28 12:11:49 +10:00
parent cd03cd4290
commit 2541973573
No known key found for this signature in database
GPG Key ID: 2B829A3DF9204DC4
15 changed files with 265 additions and 61 deletions

View File

@ -602,11 +602,23 @@ function node_theme_suggestions_node(array $variables) {
* inside "/core/modules/node/templates/node.html.twig". Look in there for the
* full list of variables.
*
* By default this function performs special preprocessing of some base fields
* so they are available as variables in the template. For example 'title'
* appears as 'label'. This preprocessing is skipped if:
* - a module makes the field's display configurable via the field UI by means
* of BaseFieldDefinition::setDisplayConfigurable()
* - AND the additional entity type property
* 'enable_base_field_custom_preprocess_skipping' has been set using
* hook_entity_type_build().
*
* @param array $variables
* An associative array containing:
* - elements: An array of elements to display in view mode.
* - node: The node object.
* - view_mode: View mode; e.g., 'full', 'teaser', etc.
*
* @see hook_entity_type_build()
* @see \Drupal\Core\Field\BaseFieldDefinition::setDisplayConfigurable()
*/
function template_preprocess_node(&$variables) {
$variables['view_mode'] = $variables['elements']['#view_mode'];
@ -615,14 +627,29 @@ function template_preprocess_node(&$variables) {
$variables['node'] = $variables['elements']['#node'];
/** @var \Drupal\node\NodeInterface $node */
$node = $variables['node'];
$variables['date'] = \Drupal::service('renderer')->render($variables['elements']['created']);
unset($variables['elements']['created']);
$variables['author_name'] = \Drupal::service('renderer')->render($variables['elements']['uid']);
unset($variables['elements']['uid']);
$skip_custom_preprocessing = $node->getEntityType()->get('enable_base_field_custom_preprocess_skipping');
// Make created, uid and title fields available separately. Skip this custom
// preprocessing if the field display is configurable and skipping has been
// enabled.
// @todo https://www.drupal.org/project/drupal/issues/3015623
// In D9 delete this code and matching template lines. Using
// $variables['content'] is more flexible and consistent.
$submitted_configurable = $node->getFieldDefinition('created')->isDisplayConfigurable('view') || $node->getFieldDefinition('uid')->isDisplayConfigurable('view');
if (!$skip_custom_preprocessing || !$submitted_configurable) {
$variables['date'] = \Drupal::service('renderer')->render($variables['elements']['created']);
unset($variables['elements']['created']);
$variables['author_name'] = \Drupal::service('renderer')->render($variables['elements']['uid']);
unset($variables['elements']['uid']);
}
if (!$skip_custom_preprocessing || !$node->getFieldDefinition('title')->isDisplayConfigurable('view')) {
$variables['label'] = $variables['elements']['title'];
unset($variables['elements']['title']);
}
$variables['url'] = !$node->isNew() ? $node->toUrl('canonical')->toString() : NULL;
$variables['label'] = $variables['elements']['title'];
unset($variables['elements']['title']);
// The 'page' variable is set to TRUE in two occasions:
// - The view mode is 'full' and we are on the 'node.view' route.
// - The node is in preview and view mode is either 'full' or 'default'.
@ -634,17 +661,24 @@ function template_preprocess_node(&$variables) {
$variables['content'][$key] = $variables['elements'][$key];
}
// Display post information only on certain node types.
$node_type = $node->type->entity;
// Used by RDF to add attributes around the author and date submitted.
$variables['author_attributes'] = new Attribute();
$variables['display_submitted'] = $node_type->displaySubmitted();
if ($variables['display_submitted']) {
if (theme_get_setting('features.node_user_picture')) {
// To change user picture settings (e.g. image style), edit the 'compact'
// view mode on the User entity. Note that the 'compact' view mode might
// not be configured, so remember to always check the theme setting first.
$variables['author_picture'] = user_view($node->getOwner(), 'compact');
if (isset($variables['date'])) {
// Display post information on certain node types. This only occurs if
// custom preprocessing occurred for both of the created and uid fields.
// @todo https://www.drupal.org/project/drupal/issues/3015623
// In D9 delete this code and matching template lines. Using a field
// formatter is more flexible and consistent.
$node_type = $node->type->entity;
// Used by RDF to add attributes around the author and date submitted.
$variables['author_attributes'] = new Attribute();
$variables['display_submitted'] = $node_type->displaySubmitted();
if ($variables['display_submitted']) {
if (theme_get_setting('features.node_user_picture')) {
// To change user picture settings (e.g. image style), edit the
// 'compact' view mode on the User entity. Note that the 'compact'
// view mode might not be configured, so remember to always check the
// theme setting first.
$variables['author_picture'] = user_view($node->getOwner(), 'compact');
}
}
}

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -75,7 +75,7 @@
<article{{ attributes }}>
{{ title_prefix }}
{% if not page %}
{% if label and not page %}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>

View File

@ -0,0 +1,40 @@
langcode: en
status: true
dependencies:
config:
- node.type.page
module:
- node
id: node.page
targetEntityType: node
bundle: page
types:
- 'schema:WebPage'
fieldMappings:
title:
properties:
- 'schema:name'
created:
properties:
- 'schema:dateCreated'
datatype_callback:
callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value'
changed:
properties:
- 'schema:dateModified'
datatype_callback:
callable: 'Drupal\rdf\CommonDataConverter::dateIso8601Value'
body:
properties:
- 'schema:text'
uid:
properties:
- 'schema:author'
mapping_type: rel
comment_count:
properties:
- 'schema:interactionCount'
datatype_callback:
callable: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
arguments:
interaction_type: UserComments

View File

@ -0,0 +1,6 @@
name: 'Node configurable display module tests'
type: module
description: 'Support module for node \Drupal\Core\Field\BaseFieldDefinition::setDisplayConfigurable() testing.'
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,28 @@
<?php
/**
* @file
* A module for testing making node base fields' displays configurable.
*/
use Drupal\Core\Entity\EntityTypeInterface;
/**
* Implements hook_entity_base_field_info_alter().
*/
function node_display_configurable_test_entity_base_field_info_alter(&$base_field_definitions, EntityTypeInterface $entity_type) {
if ($entity_type->id() == 'node') {
foreach (['created', 'uid', 'title'] as $field) {
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $base_field_definitions */
$base_field_definitions[$field]->setDisplayConfigurable('view', TRUE);
}
}
}
/**
* Implements hook_entity_type_build().
*/
function node_display_configurable_test_entity_type_build(array &$entity_types) {
// Allow skipping of extra preprocessing for configurable display.
$entity_types['node']->set('enable_base_field_custom_preprocess_skipping', TRUE);
}

View File

@ -0,0 +1,73 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
/**
* Tests making node base fields' displays configurable.
*
* @group node
*/
class NodeDisplayConfigurableTest extends NodeTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['quickedit', 'rdf'];
/**
* Sets base fields to configurable display and check settings are respected.
*/
public function testDisplayConfigurable() {
// Change the node type setting to show submitted by information.
$node_type = \Drupal::entityTypeManager()->getStorage('node_type')->load('page');
$node_type->setDisplaySubmitted(TRUE);
$node_type->save();
$user = $this->drupalCreateUser(['access in-place editing', 'administer nodes']);
$this->drupalLogin($user);
$node = $this->drupalCreateNode(['uid' => $user->id()]);
$assert = $this->assertSession();
// Check the node with Drupal default non-configurable display.
$this->drupalGet($node->toUrl());
$assert->elementTextContains('css', 'span.field--name-created', \Drupal::service('date.formatter')->format($node->getCreatedTime()));
$assert->elementTextContains('css', 'span.field--name-uid[data-quickedit-field-id="node/1/uid/en/full"]', $user->getAccountName());
$assert->elementTextContains('css', 'div.node__submitted', 'Submitted by');
$assert->elementTextContains('css', 'span.field--name-title', $node->getTitle());
// Enable module to make base fields' displays configurable.
\Drupal::service('module_installer')->install(['node_display_configurable_test']);
// Configure display.
$display = EntityViewDisplay::load('node.page.default');
$display->setComponent('uid',
[
'type' => 'entity_reference_label',
'label' => 'above',
'settings' => ['link' => FALSE],
])
->save();
// Recheck the node with configurable display.
$this->drupalGet($node->toUrl());
$assert->elementTextContains('css', 'span.field--name-created', \Drupal::service('date.formatter')->format($node->getCreatedTime()));
$assert->elementTextContains('css', 'span.field--name-uid[data-quickedit-field-id="node/1/uid/en/full"]', $user->getAccountName());
$assert->elementNotExists('css', 'span.field--name-uid a');
$assert->elementTextContains('css', 'span.field--name-title', $node->getTitle());
$assert->elementExists('css', 'span[property="schema:dateCreated"]');
// Remove from display.
$display->removeComponent('uid')
->removeComponent('created')
->save();
$this->drupalGet($node->toUrl());
$assert->elementNotExists('css', '.field--name-created');
$assert->elementNotExists('css', '.field--name-uid');
}
}

View File

@ -323,13 +323,30 @@ function rdf_preprocess_node(&$variables) {
// Adds RDFa markup for the date.
$created_mapping = $mapping->getPreparedFieldMapping('created');
if (!empty($created_mapping) && $variables['display_submitted']) {
if (!empty($created_mapping)) {
$date_attributes = rdf_rdfa_attributes($created_mapping, $variables['node']->get('created')->first()->toArray());
$rdf_metadata = [
'#theme' => 'rdf_metadata',
'#metadata' => [$date_attributes],
];
$variables['metadata'] = \Drupal::service('renderer')->render($rdf_metadata);
// Depending on whether custom preprocessing is enabled, the 'created'
// field may appear in either of two different places, so check both of
// those places here.
// @see template_preprocess_node.
if (!empty($variables['display_submitted'])) {
// If custom preprocessing is enabled, then detect if the 'created'
// field is displayed by checking the 'display_submitted' variable. In
// this case, for back-compatibility, put the metadata into a special
// variable.
$variables['metadata'] = \Drupal::service('renderer')->render($rdf_metadata);
}
elseif (isset($variables['elements']['created'])) {
// Otherwise, detect if the 'created' field is displayed by checking if
// it is present in the 'elements variable. Put the metadata into
// title_suffix, along with other metadata added by this module.
$variables['title_suffix']['rdf_meta_created'] = $rdf_metadata;
}
}
// Adds RDFa markup annotating the number of comments a node has.

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -81,11 +81,13 @@
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if label %}
<header class="node__header">
<h1 class="page-title">
{{ label }}
</h1>
</header>
{% endif %}
{{ title_suffix }}
{% if display_submitted %}

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -86,7 +86,7 @@
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if not page %}
{% if label and not page %}
<h2{{ title_attributes.addClass('node__title') }}>
<a class="node__link" href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -83,7 +83,7 @@
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if not page %}
{% if label and not page %}
<h2{{ title_attributes.addClass('node__title') }}>
<a class="node__link" href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -81,11 +81,13 @@ view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if label %}
<header class="node__header">
<h1 class="page-title">
{{ label }}
</h1>
</header>
{% endif %}
{{ title_suffix }}
{% if display_submitted %}

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -82,16 +82,18 @@
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if page %}
<header class="node__header">
<h1 class="page-title">
{{ label }}
</h1>
</header>
{% else %}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>
{% if label %}
{% if page %}
<header class="node__header">
<h1 class="page-title">
{{ label }}
</h1>
</header>
{% else %}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>
{% endif %}
{% endif %}
{{ title_suffix }}

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -81,7 +81,7 @@
<article{{ attributes.addClass(classes) }}>
<header>
{{ title_prefix }}
{% if not page %}
{% if label and not page %}
<h2{{ title_attributes.addClass('node__title') }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>

View File

@ -15,7 +15,7 @@
* Calling other methods, such as node.delete(), will result in an exception.
* See \Drupal\node\Entity\Node for a full list of public properties and
* methods for the node object.
* - label: The title of the node.
* - label: (optional) The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
@ -23,8 +23,8 @@
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - date: (optional) Themed creation date field.
* - author_name: (optional) Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
@ -84,7 +84,7 @@
<article{{ attributes.addClass(classes) }}>
{{ title_prefix }}
{% if not page %}
{% if label and not page %}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>