我知道如果使用 do_shortcode 包装器,则可以嵌套短代码,但是,法典指出:
“但是,如果使用短代码宏来包含另一个同名宏,则解析器将失败:”
有办法解决这个问题吗?
例如,如果我有一个短代码来制作 div,例如:
[div]some content in a div[/div]
我希望能够使用:
[div]
[div]a nested div[/div]
[/div]
但是使用标准的 do_shortcode 包装器将会失败。
我的临时解决方法是重复短代码,并在名称后附加 _parent 但我只能嵌套 1 层深度,除非我创建了 div_parent1、div_parent2 等...
如果您正在编写短代码,有一个简单的解决方案。 您可以编写多个调用同一函数的短代码。 我有用于创建 html 块(例如 div)的短代码,并且有几个名称为 div、block1、block2 等的短代码。
add_shortcode('div', 'devondev_block');
add_shortcode('block', 'devondev_block');
add_shortcode('block2', 'devondev_block');
它们都调用同一个函数。 只要您记住使用不同的短代码,它们就可以嵌套。
WordPress 短代码支持因尝试仅使用正则表达式进行解析而受到影响。可以使用正则表达式、有限状态机和堆栈的混合来进行这种解析。这种方法可以处理嵌套并且速度非常快,特别是当短代码很少时。 每次遇到这个我都想尝试一下。
API 是这样告诉的,因此这是不可能的:
This is a limitation of the context-free regexp parser used by do_shortcode() - it is very fast but does not count levels of nesting, so it can't match each opening tag with its correct closing tag in these cases.
最新版本(3.4.2)中涉及的功能是:
function do_shortcode($content) {
global $shortcode_tags;
if (empty($shortcode_tags) || !is_array($shortcode_tags))
return $content;
$pattern = get_shortcode_regex();
return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
}
function get_shortcode_regex() {
global $shortcode_tags;
$tagnames = array_keys($shortcode_tags);
$tagregexp = join( '|', array_map('preg_quote', $tagnames) );
// WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
return
'\\[' // Opening bracket
. '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
. "($tagregexp)" // 2: Shortcode name
. '\\b' // Word boundary
. '(' // 3: Unroll the loop: Inside the opening shortcode tag
. '[^\\]\\/]*' // Not a closing bracket or forward slash
. '(?:'
. '\\/(?!\\])' // A forward slash not followed by a closing bracket
. '[^\\]\\/]*' // Not a closing bracket or forward slash
. ')*?'
. ')'
. '(?:'
. '(\\/)' // 4: Self closing tag ...
. '\\]' // ... and closing bracket
. '|'
. '\\]' // Closing bracket
. '(?:'
. '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
. '[^\\[]*+' // Not an opening bracket
. '(?:'
. '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
. '[^\\[]*+' // Not an opening bracket
. ')*+'
. ')'
. '\\[\\/\\2\\]' // Closing shortcode tag
. ')?'
. ')'
. '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
}
您需要对简码中的内容再次进行简码。示例:
add_shortcode('div', function($attributes, $content, $tag) {
...
do_shortcode($content);
...
});
另请参阅:启用嵌套短代码的最佳方法是什么?(Wordpress SE)
只是看看:这并不能解决 WordPress 中的问题,因此不能回答您的问题。我以为直到现在这个问题都会被修复。
正如之前所解释的,Wordpress 仍然不支持相同类型的嵌套短代码。
因此您需要复制嵌套实例的短代码。
但是,您可以尝试基于通过 'the_content'
钩子添加的一些
正则表达式预处理的方法。 .
[div_1][/div_1]
function counter_suffix_to_nested_shortcodes($content, $nested_shortcodes = [])
{
// Define the regular expression pattern for the shortcodes
$pattern = '/(\[\/?[a-zA-Z0-9\-\_]+(?: [^\]]+)?(?:_\d+)?\])/is';
// Define a function to handle the replacements
$callback = function ($matches) use (&$suffixStack, &$nested_shortcodes) {
// get tag name
$tag = $matches[0];
$pattern = '/\[\/?([A-Za-z0-9\-\_]+)/';
preg_match($pattern, $tag, $tagNameMatches);
$tag_name = $tagNameMatches[1];
$last_tag='';
//$suffixStack=[];
$suffixCounter = 0;
// not in array of shortcode type: return shortcode as it is
if (!in_array($tag_name, $nested_shortcodes)) {
return $tag;
}
// Extract the shortcode name
preg_match($pattern, $tag, $tagNameMatches);
$shortcode_name = $tagNameMatches[1];
// Check if it's a closing tag
if (strpos($tag, '/' . $tag_name) !== false) {
$suffix = array_pop($suffixStack);
// Ensure the suffix is correctly placed in the closing tag
if ($suffix > 0) {
$tag = str_replace(['[/', ']'], ['[/', '_' . $suffix . ']'], $tag);
$last_tag = "[$tag_name]";
}
} else {
// Only increment suffixCounter if it's not previous tag and suffixStack is not empty/reset
if ( !empty($suffixStack) && $tag_name != $last_tag) {
$suffixCounter = count($suffixStack);
} else {
//reset counter
$suffixCounter = 0;
$suffixStack = [];
}
$suffixStack[] = $suffixCounter;
// get new shortcode retaining all attributes
$suffix = $suffixCounter > 0 ? '_' . $suffixCounter : '';
$tag = str_replace('[' . $shortcode_name, '[' . $shortcode_name . $suffix, $tag);
}
return $tag;
};
// Initialize the suffix stack and counter
$suffixStack = [];
// Perform the replacement using the callback function
$content = preg_replace_callback($pattern, $callback, $content);
return $content;
}
// pereprocess content: don't wrap shortcodes
function sanitize_nested_shortcodes($content)
{
global $nested_shortcodes;
// unwrap shortcodes in p tags
$replace = [
'<p>[' => '[',
']</p>' => ']',
'</p>[' => '[',
']<br />' => ']',
'“' => '"',
'’' => '"',
'‘' => '"',
'″' => '"'
];
// add index suffixes to nested shortcodes
$content = counter_suffix_to_nested_shortcodes(strtr($content, $replace), $nested_shortcodes);
return $content;
}
add_filter('the_content', 'sanitize_nested_shortcodes'); }
}
/**
* div_generate shortcode
* add class names and IDs
*/
function div_generate($atts, $content = null)
{
extract(shortcode_atts(
[
'class' => '',
'id' => ''
], $atts));
$cnt_filtered =
'<div id="' . $id . '" class="' . $class . '">' .
do_shortcode($content) .
'</div>';
return $cnt_filtered;
}
/**
* div_generate shortcode
* add class names and IDs
*/
function div_generate($atts, $content = null)
{
extract(shortcode_atts(
[
'class' => '',
'id' => ''
], $atts));
$cnt_filtered =
'<div id="' . $id . '" class="' . $class . '">' .
do_shortcode($content) .
'</div>';
return $cnt_filtered;
}
/**
* define nested shortcode
* names/identifieers:
* this prevents to break existing shortcodes
* to allow 20 nesting levels
*/
$nested_shortcodes = ['div'];
$nesting_max = 20;
// duplicate shortcodes
foreach($nested_shortcodes as $shortcode){
for ($i = 0; $i < $nesting_max; $i++) {
$suffix = $i === 0 ? '' : '_' . $i;
add_shortcode( $shortcode.$suffix, $shortcode.'_generate');
}
}
现在我们可以轻松地在 WP 编辑器中添加嵌套的短代码,而无需像这样手动添加后缀:
[div class="outer"]
[div class="nested-level1"]
<p>Content</p>
[div class="nested-level2"]
<p>Content</p>
[/div]
[/div]
[/div]
[div class="outer"]
[div_1 class="nested-level1"]
<p>Content</p>
[div_2 class="nested-level2"]
<p>Content</p>
[/div_2]
[/div_1]
[/div]
<div id="" class="outer">
<div id="" class="nested-level1">
<p>Content</p>
<div id="" class="nested-level2">
<p>Content</p>
</div>
</div>
</div>