jazzman/wp-performance-shortcode

0.2 2020-03-05 15:06 UTC

This package is auto-updated.

Last update: 2024-09-06 01:14:19 UTC


README

Greg Schoppe

安装

composer require jazzman/wp-performance-shortcode

一个探索性的WordPress插件,它使用三个阶段的过程重新实现Shortcodes,包括分词器、解析器和渲染器。

注意:这是一个早期概念验证。它不应在任何生产网站上使用。

为什么?

当前的短代码解析器使用单个正则表达式来解析自闭合短代码,如 [image id="14"] 和包裹短代码,如 [callout]This is some content[/callout]。由于正则表达式的局限性,这阻止了WordPress原生支持嵌套短代码,例如 [row][col]left content[/col][col]right content[/col][/row]。即使在复杂的嵌套调用 do_shortcode 功能的系统中,当前的解析器仍无法处理自嵌套短代码,如 [container type="outer"][container type="inner"]area 1[/container][container type="inner"]area 2[/container][/container]

除此之外,当前的短代码解析器在逻辑上也不一致。其规范是由解析器的技术限制定义的,而不是相反。

如何实现?

更好的短代码解析器基于Gutenberg的PHP块解析器,由Dennis Snell领导。它增加了支持匹配开标签和闭标签,以及一些特定的短代码增强,例如如果未找到闭标签,则将包裹短代码向后转换为自闭合短代码。

变更

如果你目前使用支持嵌套短代码的插件,它可能仍然可以正常工作,但是有一些变更你应该知道

更好的短代码解析器从最内层级别向外渲染嵌套短代码 这是为了满足现有短代码函数的规范,这些函数期望 $content 是一个字符串,而不是一个树结构。在更好的短代码解析器中,短代码是上下文无关的。 这意味着短代码渲染函数不知道当前内容包裹在其他短代码中。

解决上下文问题

上述变更意味着不再可能从短代码渲染回调函数内部为嵌套短代码提供上下文。有三种可能的途径来应对这一变更

修改短代码以使其成为上下文无关(首选选项)

对于类似以下结构的短代码

[post id="37"]
  [featured-image]
  [title]
  [excerpt]
[/post]

将重构为以下结构会更好

[post]
  [featured-image id="37"]
  [title id="37"]
  [excerpt id="37"]
[/post]

短代码最初并不是为上下文设计的,保持其原子性强调了其他结构的价值,例如 ACF 重叠器、私有帖子类型等。

这样的结构也可以通过私有 "模板" 帖子类型来实现,这样主帖子会有以下结构

[post id="37" template="12"/]

而相关的模板帖子会有以下结构

  [featured-image]
  [title]
  [excerpt]

通过过滤器注入上下文(备用途径)

对于某些用例,如果重构现有模式不可行,或者某些混淆因素使上下文成为必要,则渲染器提供两个过滤器,可用于向嵌套短代码提供上下文。

以下是一个如何实现上述示例结构的上下文传递的简单示例

function shortcode_context_injector( $retval, $tag, $atts, $shortcode ) {
  global $post, $my_backup_post;
  if( $tag == 'post' ) {
    if( !empty( $atts['id'] ) ) {
      $my_backup_post = $post;
      $post = get_post( $atts['id'] );
      setup_postdata( $post );
    } else {
      return ''; // in case of error, prevent all nested shortcodes from being parsed
    }
  }
  return $retval; // this is a short circuit filter. You must return the initial value for parsing to continue.
}

function shortcode_context_restorer( $retval, $tag, $atts, $shortcode ) {
  global $post, $my_backup_post;
  if( $tag == 'post' ) {
    if( !empty( $atts['id'] ) ) {
      $post = $my_backup_post;
      $my_backup_post = null;
      setup_postdata( $post );
    }
  }
  return $retval;
}

add_filter('shortcode_pre_render_nested_content',  'shortcode_context_injector', 10, 4);
add_filter('shortcode_post_render_nested_content', 'shortcode_context_restorer', 10, 4);

应注意,上述示例中,而不是使用单个临时全局变量,更完整的实现将是使用类属性,其中包含一个父上下文堆栈,可以根据需要推送和弹出。这将使具有附加上下文的自嵌套短代码结构成为可能,例如

[context-switcher context="1"]
  [inner-shortcode]
  [context-switcher context="2"]
    [inner-shortcode]
  [/context-switcher]
[/context-switcher]

禁用嵌套短代码渲染(旧选项)

如果您正在使用无法重构短代码以支持这些传递上下文方式的传统代码库,那么您最后的手段是禁用嵌套短代码的渲染,并依赖您短代码库中现有的功能来处理这些情况。

这可以在全局范围内进行,如下所示

apply_filters('shortcode_disable_nested_rendering', '__return_true');

或者针对特定短代码进行,如下所示

function disable_nesting_on_post_shortcodes( $retval, $tag ) {
  $blacklist = array('post', 'column');
  if( in_array( $tag, $blacklist ) ) {
    return true;
  }
  return $retval;
}
apply_filters('shortcode_disable_nested_rendering', 'disable_nesting_on_post_shortcodes', 10, 2);