分析 WordPress `gutenberg_render_block_core_image()` 函数的源码:它是如何处理图片区块的?

各位听众朋友们,大家好!今天老衲就来跟大家聊聊 WordPress 里那个负责把图片区块变漂亮的小家伙——gutenberg_render_block_core_image() 函数。这玩意儿藏在 WordPress 的核心代码里,专门负责把古腾堡编辑器里的图片区块渲染成咱们在网页上看到的实际图片。

咱们的目标是扒开它的源码,看看它到底做了些什么,怎么把各种图片属性,比如大小、对齐方式、链接等等,都巧妙地塞到 HTML 代码里去的。准备好了吗?咱们这就开始!

一、找到目标,锁定函数

首先,我们要找到这个gutenberg_render_block_core_image()函数。它藏身于 WordPress 核心代码的 wp-includes/blocks/image.php 文件里。打开这个文件,找到这个函数,我们就锁定了今天的目标。

二、代码剖析,逐行解读

接下来,咱们就要像解剖青蛙一样,把这个函数的源码一行一行地剖析开来,看看它到底有哪些组成部分。

<?php

/**
 * Registers the core/image block.
 *
 * @since 5.0.0
 */
function register_block_core_image() {
    register_block_type_from_metadata(
        __DIR__ . '/image',
        array(
            'render_callback' => 'gutenberg_render_block_core_image',
        )
    );
}
add_action( 'init', 'register_block_core_image' );

/**
 * Renders the `core/image` block on the server.
 *
 * @param array  $attributes The block attributes.
 * @param string $content    The block default content.
 * @param WP_Block $block      The block instance.
 * @return string The rendered HTML.
 */
function gutenberg_render_block_core_image( $attributes, $content, $block ) {
    static $block_index = 0;
    $block_index++;

    $default_size = 'medium';
    if ( isset( $attributes['sizeSlug'] ) ) {
        $default_size = $attributes['sizeSlug'];
    }

    $args = array(
        'class' => 'wp-block-image',
    );

    if ( isset( $attributes['align'] ) ) {
        $args['class'] .= ' align' . $attributes['align'];
    }

    if ( isset( $attributes['className'] ) ) {
        $args['class'] .= ' ' . $attributes['className'];
    }

    $image = null;
    if ( isset( $attributes['id'] ) ) {
        $image = wp_get_attachment_image(
            $attributes['id'],
            isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : $default_size,
            false,
            array(
                'class' => 'wp-image-' . $attributes['id'],
            )
        );
    }

    $image_style = '';
    if ( isset( $attributes['width'] ) ) {
        $image_style .= 'width:' . $attributes['width'] . 'px;';
    }
    if ( isset( $attributes['height'] ) ) {
        $image_style .= 'height:' . $attributes['height'] . 'px;';
    }

    if ( ! empty( $image_style ) ) {
        $args['style'] = $image_style;
    }

    $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none';
    $link_target      = isset( $attributes['linkTarget'] ) && $attributes['linkTarget'] === '_blank';
    $link_rel         = isset( $attributes['rel'] ) ? 'rel="' . esc_attr( $attributes['rel'] ) . '"' : '';
    $custom_url       = isset( $attributes['href'] ) ? $attributes['href'] : '';

    $figure_content = '';

    if ( ! empty( $image ) ) {
        $figure_content = $image;
    } elseif ( isset( $attributes['url'] ) ) {
        $alt_text = isset( $attributes['alt'] ) ? esc_attr( $attributes['alt'] ) : '';
        $figure_content = sprintf(
            '<img src="%1$s" alt="%2$s"%3$s />',
            esc_url( $attributes['url'] ),
            $alt_text,
            ! empty( $image_style ) ? ' style="' . esc_attr( $image_style ) . '"' : ''
        );
    }

    if ( 'none' !== $link_destination ) {
        $url = '';
        if ( 'custom' === $link_destination && ! empty( $custom_url ) ) {
            $url = $custom_url;
        } elseif ( isset( $attributes['id'] ) ) {
            if ( 'media' === $link_destination || 'attachment' === $link_destination ) {
                $url = wp_get_attachment_url( $attributes['id'] );
            }
        }

        if ( ! empty( $url ) ) {
            $figure_content = sprintf(
                '<a href="%1$s"%2$s%3$s>%4$s</a>',
                esc_url( $url ),
                $link_target ? ' target="_blank"' : '',
                $link_rel,
                $figure_content
            );
        }
    }

    $caption = '';
    if ( ! empty( $attributes['caption'] ) ) {
        $caption = sprintf(
            '<figcaption class="wp-element-caption">%1$s</figcaption>',
            wp_kses_post( $attributes['caption'] )
        );
    }

    $html = sprintf(
        '<figure%1$s>%2$s%3$s</figure>',
        empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"',
        $figure_content,
        $caption
    );

    return $html;
}

三、流程拆解,各个击破

咱们把整个函数拆解成几个关键步骤,逐个分析:

  1. 初始化和默认值:

    static $block_index = 0;
    $block_index++;
    
    $default_size = 'medium';
    if ( isset( $attributes['sizeSlug'] ) ) {
        $default_size = $attributes['sizeSlug'];
    }
    • static $block_index = 0; $block_index++; 这两行代码主要是为了跟踪区块的渲染次数,虽然在这个函数里用处不大,但可能在调试或者某些特定场景下有用。
    • $default_size = 'medium'; 设置默认的图片尺寸为 medium
    • if ( isset( $attributes['sizeSlug'] ) ) { $default_size = $attributes['sizeSlug']; } 如果区块属性中指定了 sizeSlug (比如 thumbnaillarge 等),就用指定的尺寸。
  2. 处理类名:

    $args = array(
        'class' => 'wp-block-image',
    );
    
    if ( isset( $attributes['align'] ) ) {
        $args['class'] .= ' align' . $attributes['align'];
    }
    
    if ( isset( $attributes['className'] ) ) {
        $args['class'] .= ' ' . $attributes['className'];
    }
    • $args['class'] = 'wp-block-image'; 设置基本的类名 wp-block-image
    • if ( isset( $attributes['align'] ) ) { $args['class'] .= ' align' . $attributes['align']; } 如果区块属性中有 align 属性(比如 leftcenterright),就添加相应的对齐类名。
    • if ( isset( $attributes['className'] ) ) { $args['class'] .= ' ' . $attributes['className']; } 如果区块属性中有 className 属性,就添加自定义的类名。
  3. 获取图片:

    $image = null;
    if ( isset( $attributes['id'] ) ) {
        $image = wp_get_attachment_image(
            $attributes['id'],
            isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : $default_size,
            false,
            array(
                'class' => 'wp-image-' . $attributes['id'],
            )
        );
    }
    • $image = null; 初始化 $image 变量。
    • if ( isset( $attributes['id'] ) ) { ... } 如果区块属性中有 id 属性(也就是图片附件的 ID),就使用 wp_get_attachment_image() 函数来获取图片 HTML 代码。
    • wp_get_attachment_image() 函数会根据 idsizeSlug 和其他参数生成 <img> 标签。
    • 这里还添加了一个类名 wp-image- + 图片ID,方便 CSS 定制。
  4. 处理图片样式:

    $image_style = '';
    if ( isset( $attributes['width'] ) ) {
        $image_style .= 'width:' . $attributes['width'] . 'px;';
    }
    if ( isset( $attributes['height'] ) ) {
        $image_style .= 'height:' . $attributes['height'] . 'px;';
    }
    
    if ( ! empty( $image_style ) ) {
        $args['style'] = $image_style;
    }
    • $image_style = ''; 初始化 $image_style 变量。
    • 如果区块属性中有 widthheight 属性,就将它们添加到 $image_style 变量中,形成 CSS 样式。
    • 最后,如果 $image_style 不为空,就将它添加到 $args 数组中。
  5. 处理链接:

    $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none';
    $link_target      = isset( $attributes['linkTarget'] ) && $attributes['linkTarget'] === '_blank';
    $link_rel         = isset( $attributes['rel'] ) ? 'rel="' . esc_attr( $attributes['rel'] ) . '"' : '';
    $custom_url       = isset( $attributes['href'] ) ? $attributes['href'] : '';
    
    $figure_content = '';
    
    if ( ! empty( $image ) ) {
        $figure_content = $image;
    } elseif ( isset( $attributes['url'] ) ) {
        $alt_text = isset( $attributes['alt'] ) ? esc_attr( $attributes['alt'] ) : '';
        $figure_content = sprintf(
            '<img src="%1$s" alt="%2$s"%3$s />',
            esc_url( $attributes['url'] ),
            $alt_text,
            ! empty( $image_style ) ? ' style="' . esc_attr( $image_style ) . '"' : ''
        );
    }
    
    if ( 'none' !== $link_destination ) {
        $url = '';
        if ( 'custom' === $link_destination && ! empty( $custom_url ) ) {
            $url = $custom_url;
        } elseif ( isset( $attributes['id'] ) ) {
            if ( 'media' === $link_destination || 'attachment' === $link_destination ) {
                $url = wp_get_attachment_url( $attributes['id'] );
            }
        }
    
        if ( ! empty( $url ) ) {
            $figure_content = sprintf(
                '<a href="%1$s"%2$s%3$s>%4$s</a>',
                esc_url( $url ),
                $link_target ? ' target="_blank"' : '',
                $link_rel,
                $figure_content
            );
        }
    }
    • $link_destination 决定链接的目标,可以是 none(无链接)、media(链接到媒体文件)、attachment(链接到附件页面)或 custom(自定义链接)。
    • $link_target 决定是否在新标签页打开链接。
    • $link_rel 设置链接的 rel 属性,比如 noopenernoreferrer 等。
    • $custom_url 是自定义链接的 URL。
    • 这段代码首先判断是否有图片,如果有,就将 $image 赋值给 $figure_content。如果没有,但有 URL,就创建一个 <img> 标签,并将它赋值给 $figure_content
    • 然后,根据 $link_destination 的值,决定是否将 $figure_content 包裹在一个 <a> 标签中。
  6. 处理图片描述:

    $caption = '';
    if ( ! empty( $attributes['caption'] ) ) {
        $caption = sprintf(
            '<figcaption class="wp-element-caption">%1$s</figcaption>',
            wp_kses_post( $attributes['caption'] )
        );
    }
    • 如果区块属性中有 caption 属性,就创建一个 <figcaption> 标签,并将 caption 的值包裹在其中。wp_kses_post() 函数用于对 caption 进行安全过滤。
  7. 生成最终 HTML:

    $html = sprintf(
        '<figure%1$s>%2$s%3$s</figure>',
        empty( $args['class'] ) ? '' : ' class="' . esc_attr( $args['class'] ) . '"',
        $figure_content,
        $caption
    );
    
    return $html;
    • 使用 sprintf() 函数将所有的元素组合成一个 <figure> 标签,并返回最终的 HTML 代码。

四、属性解读,抽丝剥茧

现在,咱们来详细分析一下这个函数用到的各种属性:

属性名 类型 描述
id integer 图片附件的 ID。
url string 图片的 URL。如果 id 存在,则优先使用 id 获取图片,否则使用 url
alt string 图片的 alt 属性。
caption string 图片的描述文字。
align string 图片的对齐方式,可以是 leftcenterrightwidefull
width integer 图片的宽度,单位是像素。
height integer 图片的高度,单位是像素。
linkDestination string 链接的目标,可以是 none(无链接)、media(链接到媒体文件)、attachment(链接到附件页面)或 custom(自定义链接)。
linkTarget boolean 是否在新标签页打开链接,true 表示在新标签页打开,false 表示在当前标签页打开。
href string 自定义链接的 URL。
rel string 链接的 rel 属性,比如 noopenernoreferrer 等。
sizeSlug string 图片的尺寸,可以是 thumbnailmediumlargefull
className string 自定义的 CSS 类名。

五、实战演练,举例说明

为了更好地理解这个函数,咱们来举个例子。假设咱们在古腾堡编辑器里插入了一个图片区块,并设置了以下属性:

  • id = 123
  • alt = "这是一张美丽的风景图片"
  • caption = "美丽的风景"
  • align = "center"
  • linkDestination = "media"

那么,gutenberg_render_block_core_image() 函数会生成类似下面的 HTML 代码:

<figure class="wp-block-image aligncenter">
  <a href="http://example.com/wp-content/uploads/2023/10/image.jpg">
    <img src="http://example.com/wp-content/uploads/2023/10/image-medium.jpg" alt="这是一张美丽的风景图片" class="wp-image-123" />
  </a>
  <figcaption class="wp-element-caption">美丽的风景</figcaption>
</figure>

六、总结与升华

通过对 gutenberg_render_block_core_image() 函数的源码分析,咱们可以得出以下结论:

  • 这个函数的主要作用是将图片区块的属性转换为 HTML 代码。
  • 它使用了 wp_get_attachment_image() 函数来获取图片 HTML 代码。
  • 它支持多种图片属性,比如大小、对齐方式、链接等等。
  • 它使用了 sprintf() 函数来生成最终的 HTML 代码。

掌握了这个函数的原理,咱们就可以更好地定制图片区块的样式和功能,让网站的图片更加美观和实用。

七、一点小技巧

  • 如果你想修改图片区块的默认样式,可以通过 CSS 来覆盖默认的类名。
  • 如果你想添加自定义的图片属性,可以通过 block.json 文件来定义新的属性,并在 render_callback 函数中处理这些属性。
  • 如果你想完全自定义图片区块的 HTML 代码,可以编写自己的 render_callback 函数。

好了,今天的讲座就到这里。希望大家有所收获,咱们下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注