基础篇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:

用于判断是否显示提交信息,如果显示,则打印作者名称,以及发布日期。你可以在内容类型的编辑页面找到这个选项,如下图。前面已经说过了,节点属于不同的内容类型,因此,覆写节点模板的时候,和节点所属的内容类型息息相关。

display submitted

content:他包含了节点的所有字段,按照内容类型的管理显示(admin/structure/types/manage/content-type/display)中的设置细节和顺序打印所有的字段,设置为禁用的字段则不打印,见下图,其中content-type是内容类型的机读名称。我们现在的节点属于article内容类型,因此,在模板中打印出content的时候,就会把article内容类型的所有字段都打印出来,它包括图像、标签、正文和评论。

content type manage display

很多时候,为了调整样式,你需要将某个字段单独打印出来,那么你可以使用类似这样的命令:

{{ 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>

 

本书共83小节:

评论 (4)

    • 2017-10-20

    想获取node--article.html.twig模版上的标题title变量,听了您的课程,装了devel kint 模块,写上{{ kint() }} 页面就没反应了。现在只知道page模版上的title 变量为{{ page['#title'] }},那么在node模版上怎么表示呢?{{ kint() }}撤掉就没事,写上就没反应,是我哪里搞错了吗?

    • 2017-10-21

    In reply to by silence

    label用于输出节点标题,文档中有的。   kint会消耗大量内存,因此开启之前应该先提高内存限制,详见第五节。

  • 29
    • 2018-05-27

    主题开发教程写的真不错,有的文字怎么是乱码啊

  • 你好,谢谢支持,文字做了加密,只支持符合标准的现代浏览器比如Chrome、Firefox、Edge