是否可以嵌套相同的短代码的WordPress短代码?

问题描述 投票:0回答:4

我知道如果使用 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 等...

php wordpress shortcode
4个回答
3
投票

如果您正在编写短代码,有一个简单的解决方案。 您可以编写多个调用同一函数的短代码。 我有用于创建 html 块(例如 div)的短代码,并且有几个名称为 div、block1、block2 等的短代码。

add_shortcode('div', 'devondev_block');
add_shortcode('block', 'devondev_block');
add_shortcode('block2', 'devondev_block');

它们都调用同一个函数。 只要您记住使用不同的短代码,它们就可以嵌套。

WordPress 短代码支持因尝试仅使用正则表达式进行解析而受到影响。可以使用正则表达式、有限状态机和堆栈的混合来进行这种解析。这种方法可以处理嵌套并且速度非常快,特别是当短代码很少时。 每次遇到这个我都想尝试一下。


1
投票

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]]
}

0
投票

您需要对简码中的内容再次进行简码。示例:

add_shortcode('div', function($attributes, $content, $tag) {
    ...
    do_shortcode($content);
    ...
});

另请参阅:启用嵌套短代码的最佳方法是什么?(Wordpress SE)

只是看看:这并不能解决 WordPress 中的问题,因此不能回答您的问题。我以为直到现在这个问题都会被修复。


0
投票

正如之前所解释的,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 />' => ']',
          '&#8220;' => '"',
          '&#8217;' => '"',
          '&#8216;' => '"',
          '&#8243;' => '"'
      ];
      // 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>
© www.soinside.com 2019 - 2024. All rights reserved.