另一种方法是通过临时删除短代码来预处理短代码的内容,例如在wpautop()
和do_shortcode()
对其进行操作,然后再次更换。
我相信这种方法以前已经以各种方式实现过,但我是这样玩的:
示例以下是预处理的示例:
[code lang="php"]
$foo = <<<EOT
....
EOT;
[/code]
此代码块将替换为:
[code lang="php"]code_b6a7d410d48883693b6714b68a4eee0a[/code]
参考号可以是
md5
代码块的内容。
处理do_shortcode()
和wpautop()
现在代码块的内容应该不会有问题了。
然后,我们的快捷码将输出与参考号对应的代码块。
基本实现
基本设置将注册短代码和早期预处理过滤器:
add_shortcode( $tag, [ $this, \'shortcode\' ] );
add_filter( \'the_content\', [ $this, \'filter_before\' ], 0 );
短代码定义为:
public function shortcode( $atts, $content )
{
// Default attributes
$atts = shortcode_atts( [\'lang\' => \'php\'], $atts, \'codeblock_shortcode\' );
// Restore the code block\'s content, HTML escaped it and pre-wrap it
return sprintf(
\'<pre lang="%s">%s</pre>\',
esc_attr( $atts[\'lang\'] ),
esc_html( $this->filter_after( $content ) )
);
}
其中代码块隐藏在
filter_before()
方法,并使用
filter_after()
方法然后HTML转义并最终包装在
<pre>
标签
在这种问题中,使用它很方便preg_replace
通过回调。
演示插件这里有一个演示插件:
<?php
/**
* Plugin Name: Simple Code Block
* Description: Support for the [code] shortcode to display code snippets.
* Plugin URI: http://wordpress.stackexchange.com/a/233740/26350
* Author: birgire
* Version: 1.0.0
*/
namespace WPSE\\SimpleCodeBlock;
add_action( \'init\', function()
{
$o = new CodeBlock;
$o->init( $tag = \'code\' );
} );
class CodeBlock
{
private $blocks;
private $tag;
public function init( $tag )
{
if( ! shortcode_exists( $tag ) && preg_match( \'#^[a-z]+$#\', $tag ) )
{
$this->tag = $tag;
$this->blocks = [];
add_shortcode( $tag, [ $this, \'shortcode\' ] );
add_filter( \'the_content\', [ $this, \'filter_before\' ], 0 );
}
}
public function filter_before( $content )
{
if( $this->has_code_block( $content ) )
{
$tag = preg_quote( $this->tag );
$pattern = "#(\\[{$tag}(\\s+[^\\]]+)?\\])(.*?)(\\[\\/{$tag}\\])#s";
$content = preg_replace_callback(
$pattern,
[ $this, \'regex_before\' ],
$content
);
}
return $content;
}
public function filter_after( $content )
{
if( $this->has_code_key( $content ) )
{
$tag = preg_quote( $this->tag );
$pattern = "#{$tag}\\_[a-z0-9]{32}#";
$content = preg_replace_callback(
$pattern,
[ $this, \'regex_after\' ],
$content
);
}
return $content;
}
public function regex_before ( Array $matches )
{
// Nothing to do
if( 5 !== count( $matches ) )
return;
// Generate a key from the code block\'s content
$key = $this->tag . \'_\' . md5( $matches[3] );
// Temporarily store the code block
$this->blocks[$key] = $matches[3];
// Return this form [code ...]code_b6a7d410d48883693b6714b68a4eee0a[/code]
return $matches[1] . $key . $matches[4];
}
public function regex_after( Array $matches )
{
$key = $matches[0];
// Restore the code block\'s content
if( isset( $this->blocks[$key] ) )
return $this->blocks[$key];
return;
}
public function shortcode( $atts = [], $content = \'\' )
{
// Default attributes
$atts = shortcode_atts( [\'lang\' => \'php\'], $atts, \'codeblock_shortcode\' );
// Restore the code block\'s content, HTML escaped it and pre-wrap it
return sprintf(
\'<pre lang="%s">%s</pre>\',
esc_attr( $atts[\'lang\'] ),
esc_html( $this->filter_after( $content ) )
);
}
private function has_code_key( $content )
{
return false !== strpos( $content, $this->tag . \'_\' );
}
private function has_code_block( $content )
{
return false !== strpos( $content, \'[\' . $this->tag );
}
} // end class
也可以稍微调整一下,这样
[code]
未定义为短代码,并以以下优先级还原代码块的内容
PHP_INT_MAX
在
the_content
滤器