基础篇31. 内容的覆写(中)
{#
/**
* @file
* Theme override to display a node.
*
* Available variables:
* - node: The node entity with limited access to object properties and methods.
* Only method names starting with "get", "has", or "is" and a few common
* methods such as "id", "label", and "bundle" are available. For example:
* - node.getCreatedTime() will return the node creation timestamp.
* - node.hasField('field_example') returns TRUE if the node bundle includes
* field_example. (This does not indicate the presence of a value in this
* field.)
* - node.isPublished() will return whether the node is published or not.
* 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.
* - 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
* of a given child element.
* - 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.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - node: The current template type (also known as a "theming hook").
* - node--type-[type]: The current node type. For example, if the node is an
* "Article" it would result in "node--type-article". Note that the machine
* name will often be in a short form of the human readable label.
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
* teaser would result in: "node--view-mode-teaser", and
* full: "node--view-mode-full".
* The following are controlled through the node publishing options.
* - node--promoted: Appears on nodes promoted to the front page.
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
* teaser listings.
* - node--unpublished: Appears on unpublished nodes visible only to site
* admins.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - content_attributes: Same as attributes, except applied to the main
* content tag that appears in the template.
* - author_attributes: Same as attributes, except applied to the author of
* the node tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
* - view_mode: View mode; for example, "teaser" or "full".
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
* - readmore: Flag for more state. Will be true if the teaser content of the
* node cannot hold the main body content.
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* @see template_preprocess_node()
*
* @todo Remove the id attribute (or make it a class), because if that gets
* rendered twice on a page this is invalid CSS for example: two lists
* in different view modes.
*/
#}
<article{{ attributes }}>
{{ title_prefix }}
{% if not page %}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>
{% endif %}
{{ title_suffix }}
{% if display_submitted %}
<footer>
{{ author_picture }}
<div{{ author_attributes }}>
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
{{ metadata }}
</div>
</footer>
{% endif %}
<div{{ content_attributes }}>
{{ content }}
</div>
</article>
这是上一节我们覆写的节点模板。
模板中的注释为我们提供了比较详细的文档,你可以在注释中找到各个变量的定义和用法。
这里我们挑选几个最重要的讲一下:
page: 这里的page用于判断是否是节点页面,比如,节点1,是我们输入的第一个节点。当这个节点被显示在列表中的时候,比如首页的列表,它就不是一个页面,而是一个摘要,英文叫做teaser;因此,我们这个node模板,通过判断是否为page,即可以控制节点页面的html,也可以控制节点摘要的html。
当然,你也可以不使用判断,而直接使用node--[内容类型]--teaser.html.twig这个模板来直接控制节点在内容列表中的效果。这样的话,你就不需要在node模板中去为两种情况写代码。
label:用于输出节点的标题。我们可以看到代码中只在节点为teaser状态下才输出标题,在页面状态下没有输出标题,这是因为,在页面上,有一个核心提供的标题区块。我们通常会可以关闭这个区块,并在node模板中使用label变量来输出标题。在这里,我们用bootstrap为我们提供的文字居中类名text-align-center来让标题居中。而且,由于这里是页面的标题,因此,不需要像在teaser中那样,放一个链接。
title_prefix
title_suffix
这两个是为其它模块预留的,他们各自在标题的前面和后面插入其它模块想要输出的东西,你不应该删除他们。比如Contextual Links模块,会在标题的打印一个用来编辑节点的钢笔图标。如果你把这两条代码删除了,相应的图标就会消失。
display_submitted:
用于判断是否显示提交信息,如果显示,则打印作者名称,以及发布日期。你可以在内容类型的编辑页面找到这个选项,如下图。前面已经说过了,节点属于不同的内容类型,因此,覆写节点模板的时候,和节点所属的内容类型息息相关。
content:他包含了节点的所有字段,按照内容类型的管理显示(admin/structure/types/manage/content-type/display)中的设置细节和顺序打印所有的字段,设置为禁用的字段则不打印,见下图,其中content-type是内容类型的机读名称。我们现在的节点属于article内容类型,因此,在模板中打印出content的时候,就会把article内容类型的所有字段都打印出来,它包括图像、标签、正文和评论。
很多时候,为了调整样式,你需要将某个字段单独打印出来,那么你可以使用类似这样的命令:
{{ content.field_name }}
在content后面用点连接字段的机器名。你可以在内容类型的字段列表页面查看每一个字段的机器名。通过这种方式打印出的字段,依然遵循内容类型的管理显示(admin/structure/types/manage/content-type/display)中的设置细节,比如是否打印标签,标签的位置,以及字段的格式等。
因此,这里我们用上面的语法来打印图片和正文字段。并且把图片放到一对div里面,并且给这个div一个前面用过的css类名,来使得图片居中。
此处,新手很容易犯一个错误:在node页面模板中,用上面的代码去打印所有的字段。这样做的坏处是,如果其他网站管理员为这个内容类型新增加了一个字段的话,这个新字段就无法被显示出来了。这样就会导致网站功能的缺失。作为一个themer,你的行为不应该影响网站的功能。
因此,为了避免这种错误,我们还是要把content打印出来,然后用without去掉之前已经打印过的字段,这样的话,以后新添加的字段还是会被这条代码打印出来。
{{ content|without('field_image','body','comment','field_tags') }}
注意这里,我们除了把图片和正文排除了之外,还排除了评论和标签。这样,页面上就不会打印评论和标签字段。这里这也做只是为了节省时间,因为,你应该在内容类型的管理显示页面去禁用不需要的字段。
另外,值得注意的是,在这个管理显示的页面上,还可以调整字段打印的顺序,但是这个功能只有在你使用content打印所有字段的时候才生效。如果你在模板中使用content.field_name单独打印了某个字段的话,它的顺序由它在模板文件中出现的位置来决定。
然后我们再把下面这些用于输出字段的代码全部放到一个if判断中,只用在页面上才打印这些字段,而摘要的部分,也应该放在另一个if判断中,并且还要调整一下title prefix 和 suffix的位置。最后,不要忘记关闭新添加的if语句。
然后我们回到区块布局页面,禁用page title区块,就可以避免页面上标题重复两次的现象。当然,你还可以调整编辑菜单的样式,这里就省略了。
以下是修改之后的node--article.html.twig模板的代码(未优化):
{#
/**
* @file
* Theme override to display a node.
*
* Available variables:
* - node: The node entity with limited access to object properties and methods.
* Only method names starting with "get", "has", or "is" and a few common
* methods such as "id", "label", and "bundle" are available. For example:
* - node.getCreatedTime() will return the node creation timestamp.
* - node.hasField('field_example') returns TRUE if the node bundle includes
* field_example. (This does not indicate the presence of a value in this
* field.)
* - node.isPublished() will return whether the node is published or not.
* 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.
* - 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
* of a given child element.
* - 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.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - node: The current template type (also known as a "theming hook").
* - node--type-[type]: The current node type. For example, if the node is an
* "Article" it would result in "node--type-article". Note that the machine
* name will often be in a short form of the human readable label.
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
* teaser would result in: "node--view-mode-teaser", and
* full: "node--view-mode-full".
* The following are controlled through the node publishing options.
* - node--promoted: Appears on nodes promoted to the front page.
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
* teaser listings.
* - node--unpublished: Appears on unpublished nodes visible only to site
* admins.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - content_attributes: Same as attributes, except applied to the main
* content tag that appears in the template.
* - author_attributes: Same as attributes, except applied to the author of
* the node tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
* - view_mode: View mode; for example, "teaser" or "full".
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
* - readmore: Flag for more state. Will be true if the teaser content of the
* node cannot hold the main body content.
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* @see template_preprocess_node()
*
* @todo Remove the id attribute (or make it a class), because if that gets
* rendered twice on a page this is invalid CSS for example: two lists
* in different view modes.
*/
#}
{% if not page %}
<article{{ attributes }}>
{{ title_prefix }}
<h2{{ title_attributes }}>
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
</h2>
{{ title_suffix }}
{% endif %}
{% if page %}
<article{{ attributes }}>
<h1 class="text-align-center">
{{ title_prefix }}
{{ label }}
{{ title_suffix }}
</h1>
<div{{ content_attributes }}>
<div class="text-align-center">
{{ content.field_image }}
</div>
{{ content.body }}
</div>
{% if display_submitted %}
<footer>
{{ author_picture }}
<div{{ author_attributes }}>
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
{{ metadata }}
</div>
</footer>
{% endif %}
{{ content|without('field_image','body','comment','field_tags') }}
{% endif %}
</article>
初学者(特别是中文使用者)经常遇到的另一个问题是如何修改此处发布时间的格式,因为中文格式和英文格式的习惯是不一样的。在”日期和时间格式“的设置页面(/admin/config/regional/date-time),你可以添加自定义的时间格式,添加时会产生一个机读名称。假设这个机读名称是”my_custom_format“。
那么,你可以在node模板中用下面的语句来设置一个新的变量:
{% set createdDate = node.getCreatedTime|format_date('my_custom_format') %}
然后再把上面106行中的{{ date }}改成你新创建的变量 {{ createdDate }}。用同样的方法,也可以把时间按照其他格式打印出来,这里就不详细举例了。”默认中等日期“的机读名称是medium,html日期的机读名称是html_date。
或者,你也可以跳过Drupal自己的时间格式设置,直接在你的模板中设置格式,方法如下:
{% set createdDate = node.getCreatedTime|date('j F Y') %}
{% trans %}Submitted by {{ author_name }} on {{ createdDate }} {% endtrans %}
关于此处的j F Y 的含义,请参考php手册中的相关内容。
| 是一个filter,见https://www.drupal.org/node/2357633
In reply to 想获取node--article.html… by silence
In reply to 主题开发教程写的真不错,有的文字怎么是乱码啊 by weixin