简码 API

简码 API(Shortcode API)是一套用于为 WordPress 简码(shortcodes)创建简单函数的集合,以便在文章和页面中使用。例如,以下简码(位于文章或页面的正文中)将添加一个包含附加到该文章或页面的图片的相册:[ gallery ]

该 API 使插件开发者能够创建特殊类型的內容(如表单、内容生成器),用户只需在页面文本中添加相应的简码即可将其附加到特定页面。

简码 API 使得创建支持如下属性的简码变得非常容易:

[ gallery id="123" size="medium" ]

该 API 处理所有复杂的解析工作,无需为每个简码编写自定义正则表达式。API 还提供了设置和获取默认属性的辅助函数。该 API 同时支持自闭合和闭合简码。

对于急于上手的开发者,以下是创建简码所需的 PHP 代码的最小示例:

// [foobar]
function wporg_foobar_func( $atts ) {
	return "foo and bar";
}
add_shortcode( 'foobar', 'wporg_foobar_func' );

这将创建一个返回“foo and bar"的[foobar]简码。

带属性时:

// [bartag foo="foo-value"]
function bartag_func( $atts ) {
	$a = shortcode_atts( array(
		'foo' => 'something',
		'bar' => 'something else',
	), $atts );

	return "foo = {$a['foo']}";
}
add_shortcode( 'bartag', 'bartag_func' );

这将创建一个支持两个属性:“foo"和“bar"的[bartag]简码。这两个属性都是可选的,如果未提供,将采用默认选项[foo="something" bar="something else"]。该简码将返回foo = {foo 属性的值}。

历史

简码 API 于 WordPress 2.5 版本中引入。

概述

简码通过提供一个处理器函数来编写。简码处理器与 WordPress 过滤器大致相似:它们接受参数(属性)并返回结果(简码输出)。

简码名称应全部使用小写字母,但数字和下划线也可以使用。请小心使用连字符(破折号),最好避免使用它们。

add_shortcode函数用于注册简码处理器。它接受两个参数:简码名称(在文章正文中使用的字符串)和回调函数名。

有三个参数传递给简码回调函数。您可以选择使用其中任意数量,包括不使用任何参数。

  • $atts:属性关联数组,如果没有提供属性则为空字符串
  • $content:闭合内容(如果简码以闭合形式使用)
  • $tag:简码标签,用于共享回调函数很有用

注册简码处理器的 API 调用可能如下所示:

add_shortcode( 'wporgshortcode', 'wporg_shortcode_handler' );

当显示the_content时,简码 API 将解析任何注册的简码(如[myshortcode]),分离并解析属性和内容(如果有),并将它们传递给相应的简码处理器函数。简码处理器返回的任何字符串(不是输出)都将被插入到文章正文中,替换简码本身。

简码属性输入方式如下:

[wporgshortcode foo="bar" bar="bing"]

这些属性将被转换为如下关联数组,作为$atts参数传递给处理器函数:

array( 'foo' => 'bar', 'bar' => 'bing' )

数组键是属性名称;数组值是相应的属性值。此外,第零个条目($atts[0])将保存匹配简码正则表达式的字符串,但仅当它与回调名称不同时。

处理属性

原始$atts数组可能包含用户指定的任何任意属性。(此外,数组的第零个条目可能包含被正则表达式识别的字符串;见下方说明。)

为了帮助为缺失的属性设置默认值,并消除简码无法识别的任何属性,API 提供了shortcode_atts()函数。

shortcode_atts()类似于wp_parse_args函数,但有一些重要区别。其参数为:

shortcode_atts( $defaults_array, $atts );

两个参数都是必需的。$defaults_array是一个关联数组,指定已识别的属性名称及其默认值。$atts是作为原始属性数组传递给您的简码处理器的数组。shortcode_atts()将返回一个标准化数组,其中包含来自$defaults_array的所有键,如果存在则填充来自$atts数组的值。例如:

$a = shortcode_atts( array(
	'title' => 'My Title',
	'foo' => 123,
), $atts );

如果$atts包含array( 'foo' => 456, 'bar' => 'something' ),则生成的$a将为array( 'title' => 'My Title', 'foo' => 456 )。$atts['foo']的值覆盖默认值 123。$atts['title']未设置,因此使用默认值"My Title"。默认数组中没有"bar"项,因此不包含在结果中。

属性名称在传递给处理器函数之前始终转换为小写。值保持不变。[myshortcode FOO="BAR"]产生$atts = array( 'foo' => 'BAR' )。

在简码处理器中声明默认值和解析属性的建议代码惯例如下:

function wporg_shortcode_handler( $atts, $content = null ) {
	$a = shortcode_atts( array(
		'attr_1' => 'attribute 1 default',
		'attr_2' => 'attribute 2 default',
		// ...etc
	), $atts );
}

这将解析属性,设置默认值,消除任何不支持的属性,并将结果存储在名为$a的局部数组变量中,属性作为键——$a['attr_1']、$a['attr_2']等。换句话说,默认值数组近似于局部变量声明列表。

重要提示 – 不要对$atts属性名使用驼峰命名法或全大写字母:

$atts值在shortcode_atts( array( 'attr_1' => 'attr_1 default', // ...etc ), $atts )处理期间会被转换为小写,因此您可能希望仅使用小写。

关于混淆的正则表达式/回调名称引用的说明:

属性数组的第零个条目(**$atts[0]**)将包含匹配简码正则表达式的字符串,但仅当它与回调名称不同时,否则它将作为回调函数的第三个参数出现。

add_shortcode('foo','foo'); // two shortcodes referencing the same callback
 add_shortcode('bar','foo');
    produces this behavior:
 [foo a='b'] ==> callback to: foo(array('a'=>'b'),NULL,"foo");
 [bar a='c'] ==> callback to: foo(array(0 => 'bar', 'a'=>'c'),NULL,"");

这令人困惑,也许反映了潜在的 bug,但重载的回调例程可以通过检查回调的第三个参数和第零个属性来正确确定使用了哪个简码来调用它。(让两个简码引用同一个回调例程并不是错误,这允许共用代码。)

输出

简码处理器函数的返回值将插入到文章内容的输出中,替换简码宏。请记住使用 return 而不是 echo – 任何被输出的内容都将输出到浏览器,但不会出现在页面上的正确位置。

简码在wpautop和wptexturize应用后处理格式之后进行解析。这意味着您的简码输出 HTML 不会自动应用弯引号、添加 p 和 br 标签等。如果您确实希望简码输出得到格式化,应在从简码处理器返回输出时直接调用wpautop()或wptexturize()。

wpautop 识别简码语法,并尝试不将 p 或 br 标签包裹在单独一行的简码周围。打算以此方式使用的简码应确保输出被适当的块标签(如<p>或<div>)包裹。

如果短代码产生大量 HTML,则可以使用 ob_start 捕获输出并将其转换为字符串,如下所示:

function wporg_shortcode() {
	ob_start();
	?> <HTML> <here> ... <?php
	return ob_get_clean();
}

闭合与自闭合短代码

上述示例展示了自闭合短代码宏,例如 [myshortcode]。API 也支持闭合短代码,例如 [myshortcode]content[/myshortcode]。

如果使用短代码宏来包裹内容,其处理函数将接收一个包含该内容的第二个参数。用户可能以两种形式编写短代码,因此必须通过为处理函数的第二个参数提供默认值来兼容这两种情况:

function wporg_shortcode_handler( $atts, $content = null )

可以使用 empty( $content ) 来区分自闭合和闭合的情况。

当内容被包裹时,完整的短代码宏(包括其内容)将被替换为函数输出。处理函数有责任对原始内容字符串进行必要的转义或编码,并将其包含在输出中。

以下是一个简单的闭合短代码示例:

function wporg_caption_shortcode( $atts, $content = null ) {
	return '<span class="caption">' . $content . '</span>';
}
add_shortcode( 'caption', 'wporg_caption_shortcode' );

像这样使用时:

My Caption

输出将是:

<span class="caption">My Caption</span>

由于 $content 在不进行任何转义或编码的情况下包含在返回值中,用户可以包含原始 HTML:

<a href="http://example.com/">My Caption</a>

这将生成:

<span class="caption"><a href="http://example.com/">My Caption</a></span>

这可能符合也可能不符合预期行为——如果短代码不应允许在其输出中包含原始 HTML,则应使用转义或过滤函数在处理结果返回前进行处理。

短代码解析器对帖子内容只进行一次遍历。这意味着如果短代码处理函数的 $content 参数包含另一个短代码,它不会被解析:

Caption: [myshortcode]

这将生成:

<span class="caption">Caption: [myshortcode]</span>

如果闭合短代码旨在允许在其输出中使用其他短代码,则处理函数可以递归调用 do_shortcode():

function wporg_caption_shortcode( $atts, $content = null ) {
    return '<span class="caption">' . do_shortcode($content) . '</span>';
}

在前面的示例中,这将确保包裹内容中的 [myshortcode] 宏被解析,并且其输出被 caption span 包裹:

<span class="caption">Caption: The result of myshortcode's handler function</span>

解析器不会像您期望的那样处理同一短代码的闭合与非闭合形式的混合。例如,如果您有:

[myshortcode example='non-enclosing' /] non-enclosed content [myshortcode] enclosed content [/myshortcode]

解析器不会将其视为由文本"non-enclosed content"分隔的两个短代码,而是将其视为单个短代码,包裹着"non-enclosed content [myshortcode] enclosed content"。

闭合短代码支持与自闭合短代码相同的属性。以下是改进后的 caption_shortcode() 以支持'class'属性的示例:

function wporg_caption_shortcode( $atts, $content = null ) {
	$a = shortcode_atts( array(
		'class' => 'caption',
	), $atts );

	return '<span class="' . esc_attr($a['class']) . '">' . $content . '</span>';
}
My Caption
<span class="headline">My Caption</span>

其他功能简介

  • 解析器支持 XHTML 风格的闭合短代码,如 [myshortcode /],但这是可选的。
  • 短代码宏可以使用单引号或双引号作为属性值,或者如果属性值不包含空格,可以完全省略引号。[myshortcode foo='123' bar=456] 等同于 [myshortcode foo="123" bar="456"]。注意最后一个位置的属性值不能以正斜杠结尾,因为上一段提到的特性会消耗该斜杠。
  • 为了与旧的非正式短代码向后兼容,可以省略属性名。如果属性没有名称,它将在 $atts 数组中获得一个位置数字键。例如,[myshortcode 123] 将生成 $atts = array( 0 => 123 )。位置属性可以与命名属性混合使用,如果值包含空格或其他重要字符,可以使用引号。
  • 短代码 API 包含测试用例。这些测试(包含许多错误情况和异常语法的示例)位于 http://svn.automattic.com/wordpress-tests/trunk/tests/shortcode.php

函数参考

以下 Shortcode API 函数可用:

function add_shortcode( $tag, $func )

注册一个新的短代码处理函数。$tag 是用户编写的短代码字符串(不带花括号),例如"myshortcode"。$func 是处理函数的名称。

给定的短代码只能存在一个处理函数。再次调用 add_shortcode() 并使用相同的 $tag 名称将覆盖之前的处理程序。

function remove_shortcode( $tag )

注销现有的短代码。$tag 是在 add_shortcode() 中使用的短代码名称。

function remove_all_shortcodes()

注销所有短代码。

function shortcode_atts( $pairs, $atts )

根据 $pairs 中指定的默认值集处理原始属性数组 $atts。返回一个数组。结果将包含来自 $pairs 的每个键,并与 $atts 中的值合并。$atts 中不存在于 $pairs 中的任何键都将被忽略。

function do_shortcode( $content )

解析 $content 字符串中的任何已知短代码宏。返回一个字符串,其中包含原始内容,短代码宏已被其处理函数的输出替换。

do_shortcode() 已注册为 'the_content' 的默认过滤器,优先级为 11。

限制

嵌套短代码

短代码解析器正确处理嵌套的短代码宏,前提是它们的处理函数通过递归调用 do_shortcode() 来支持它:

[tag-a]
   [tag-b]
      [tag-c]
   [/tag-b]
[/tag-a]

但是,如果短代码宏用于包裹同名的另一个宏,解析器将会失败:

[tag-a]
   [tag-a]
   [/tag-a]
[/tag-a]

这是 do_shortcode() 所使用的无上下文正则表达式解析器的局限性——它非常快,但不计算嵌套层级,因此在这些情况下无法将每个 opening tag 与其正确的 closing tag 匹配。

在 WordPress 的未来版本中,具有嵌套短代码语法的插件可能需要确保 wptexturize() 处理器不会干扰内部代码。建议对于此类复杂语法,应在外部标签上使用 no_texturize_shortcodes 过滤器。在本例中,应将 tag-a 添加到不执行 texturize 的短代码列表中。如果 tag-a 或 tag-b 的内容仍然需要 texturize,则可以按照上述描述在调用 do_shortcode() 之前调用 wptexturize()。

未注册的名称

一些插件作者选择不注册短代码名称,例如为了在父短代码的处理函数被调用之前禁用嵌套短代码。这可能会产生意想不到的后果,例如无法解析短代码属性值。例如:

[tag-a unit="north"]
   [tag-b size="24"]
      [tag-c color="red"]
   [/tag-b]
[/tag-a]

从 4.0.1 版本开始,如果插件未能将 tag-b 和 tag-c 注册为有效的短代码,wptexturize() 处理器将在解析任何短代码之前输出以下文本:

[tag-a unit="north"]
   [tag-b size="24"]
      [tag-c color="red"]
   [/tag-b]
[/tag-a]

未注册的简码应被视为普通纯文本,没有特殊含义,因此不鼓励使用未注册的简码。如果您必须在简码标签之间包裹原始代码,至少应考虑使用 no_texturize_shortcodes 过滤器以防止标签内容被格式化:

add_shortcode( 'tag-a', 'wporg_tag_a_handler' );
add_filter( 'no_texturize_shortcodes', 'wporg_ignore_tag_a' );

function wporg_ignore_tag_a( $list ) {
  $list[] = 'tag-a';
  return $list;
}

未闭合的简码

在某些情况下,简码解析器无法正确处理已闭合和未闭合简码的混合使用。例如在这种情况下,解析器将只能正确识别第二个简码实例:

[tag]
[tag]
   CONTENT
[/tag]

但在以下情况下,解析器将能识别两者:

[tag]
   CONTENT
[/tag]
[tag]

连字符

在使用简码名称中的连字符时要小心。在以下示例中,WordPress 可能会将第二个开标签视为与第一个等价(基本上 WordPress 只看到连字符之前的第一部分):

[tag]
[tag-a]

这完全取决于哪个简码先被定义。如果您打算使用连字符,请先定义最短的简码。

为避免此问题,请使用下划线或不使用分隔符:

[tag]
[tag_a]

[tag]
[taga]

如果简码的第一部分彼此不同,则可以使用连字符:

[tag]
[tagfoo-a]

重要提示:使用连字符可能会产生您未意识到的影响;例如,如果其他安装的简码也使用了连字符,那么使用带有连字符的通用词可能会导致冲突(如果在同一个请求中一起使用简码):

// plugin-A
[is-logged-in]

// plugin-B
[is-admin]

方括号

简码解析器不接受属性内的方括号。因此以下内容将失败:

[tag attribute="[Some value]"]

由装饰性括号包围的标签尚未被 wptexturize() 或其过滤器完全支持。这些代码可能会产生意外结果:

[I put random text near my captions. ]

注意:这些限制在未来版本的 WordPress 中可能会发生变化,您应该进行测试以确保万无一失。

HTML

从版本 3.9.3 开始,简码属性内的 HTML 使用受到限制。例如,以下简码将无法正常工作,因为它包含 > 字符:

[tag value1="35" value2="25" compare=">"]

版本 4.0 旨在允许经过验证的 HTML,因此以下内容可以工作:

[tag description="<b>Greetings</b>"]

对于 HTML 限制的推荐变通方法是:对所有用户输入使用 HTML 编码,然后在自定义简码处理程序中添加 HTML 解码。计划添加额外的 API 函数。

简码属性中使用 HTML 从未得到官方支持,未来版本也不会扩展此功能。

从版本 4.2.3 开始,对 HTML 内使用简码施加了类似的限制。例如,以下简码将无法正常工作,因为它嵌套在脚本属性中:

<a onclick="[tag]">

对于动态属性的推荐变通方法是设计一个输出所有所需 HTML 而非单个值的简码。这样会更好:

[link onclick="tag"]

还要注意,由于属性引用不正确,以下简码不再被允许:

<a title="[tag attr="id"]">

要将此解析为有效的 HTML,唯一的方法是使用单引号和双引号进行嵌套:

<a title="[tag attr='id']">

注册数量

已知当注册数百个简码时,API 会变得不稳定。插件作者应创建仅依赖少量简码名称的解决方案。此限制在未来版本中可能会发生变化。

正式语法

WordPress 简码不使用与 HTML 相同的特殊字符。方括号乍看之下似乎很神奇,但它们实际上不属于任何语言的一部分。例如:

[gallery]

Gallery 简码被 API 解析为特殊符号,因为它是已注册的简码。另一方面,当简码未注册时,方括号将被忽略:

[randomthing]

randomthing 符号及其方括号会被忽略,因为它们不是任何已注册简码的一部分。

在一个理想的世界里,任何 [*] 符号都可以由 API 处理,但我们必须考虑以下挑战:方括号在 HTML 中是允许的且不总是简码,尖括号仅在有限情况下允许出现在简码内,且所有这些代码在输出前都必须通过多层可定制的过滤器和解析器。由于这些语言兼容性问题,方括号不能变得“神奇”。

简码语法使用以下一般部分:

[name attributes close]
[name attributes]Any HTML or shortcode may go here.[/name]

转义的简码结构相同,但恰好多了两个括号:

[[name attributes close]]
[[name attributes]Any HTML or shortcode may go here.[/name]]

再次强调,简码名称必须注册,否则上述四个示例都将被忽略。

名称

简码名称绝不应包含以下字符:

  • 方括号:[ ]
  • 尖括号:< >
  • 连字号:&
  • 正斜杠:/
  • 空白字符:空格、换行符、制表符
  • 不可打印字符:x00 – x20

建议避免在简码名称中使用引号。

属性

属性是可选的。简码名称与简码属性之间需要一个空格。当使用多个属性时,每个属性之间必须至少用一个空格分隔。

每个属性应符合以下格式之一:

attribute_name = 'value'
attribute_name = "value"
attribute_name = value
"value"
value

属性名称是可选的,为了在所有平台上的兼容性,应仅包含以下字符:

  • 大小写字母:A-Z a-z
  • 数字:0-9
  • 下划线:_
  • 连字符:-

属性名称中不允许有空格。名称和 = 符号之间可以使用可选的空格。= 符号和值之间也可以使用可选的空格。

需要注意的是,尽管在编辑器中可以使用混合大小写的属性,但解析后它们将始终为小写。

属性值绝不应包含以下字符:

  • 方括号:[ ]
  • 引号:", '

未引用的值也不得包含空格。

HTML 字符 < 和 > 在属性中仅受有限支持。

转义简码属性中特殊字符的推荐方法是 HTML 编码。最重要的是,出现在简码属性中的任何用户输入都必须转义或移除特殊字符。

请注意,双引号允许出现在单引号值内,反之亦然,但在处理用户输入时不建议这样做。

以下字符,如果未在属性值中转义,将被自动移除并转换为空格:

  • 不换行空格:xC2xA0
  • 零宽空格:xE2x80x8B

自闭合

自闭合标记(单个正斜杠)是可选的。标记前的空格也是可选的。标记后不允许有空格。

[example /]

自闭合标记纯粹是装饰性的,除了强制简码解析器忽略其后的任何闭合标签外,没有其他效果。

成对简码不能使用自闭合标记。

转义

WordPress 尝试在 [name] 和 [/name] 标签之间插入弯引号。它会像处理其他内容一样处理该内容。从 4.0.1 版本开始,未注册的简码也会被“格式化”,这可能会产生意外的弯引号:

[randomthing param="test"]

更好的示例是:

<code>[randomthing param="test"]</code>

为了避免使用弯引号,始终避免使用<code>元素。

注册的短代码仍会在<code>元素内进行处理。若要转义注册的短代码以在网站上显示,语法如下:

[[caption param="test"]]

这将输出:

[caption param="test"]

在这种情况下,<code>元素是可选的。

对于嵌套的短代码,请使用以下语法:

[[caption]My Caption]

外部资源

默认短代码

短代码 API 函数列表