【问题标题】:Parse Wordpress like Shortcode像简码一样解析 Wordpress
【发布时间】:2013-03-31 22:23:06
【问题描述】:

我想用属性解析像 Wordpress 这样的短代码:

输入:

[include file="header.html"]

我需要输出为数组、函数名“包含”以及带有值的属性,我们将不胜感激。

谢谢

【问题讨论】:

  • 请尝试我的库,它是独立的并且已经在生产中经过实战测试:github.com/thunderer/Shortcode。如果您需要什么,请告诉我!
  • @TomaszKowalczyk 谢谢! :)

标签: php


【解决方案1】:

这是我们在项目中使用的实用程序类 它将匹配字符串中的所有短代码(包括 html),并输出一个关联数组,包括它们的 nameattributescontent

final class Parser {

    // Regex101 reference: https://regex101.com/r/pJ7lO1
    const SHORTOCODE_REGEXP = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\@\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";

    // Regex101 reference: https://regex101.com/r/sZ7wP0
    const ATTRIBUTE_REGEXP = "/(?<name>\\S+)=[\"']?(?P<value>(?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?/u";

    public static function parse_shortcodes($text) {
        preg_match_all(self::SHORTOCODE_REGEXP, $text, $matches, PREG_SET_ORDER);
        $shortcodes = array();
        foreach ($matches as $i => $value) {
            $shortcodes[$i]['shortcode'] = $value['shortcode'];
            $shortcodes[$i]['name'] = $value['name'];
            if (isset($value['attrs'])) {
                $attrs = self::parse_attrs($value['attrs']);
                $shortcodes[$i]['attrs'] = $attrs;
            }
            if (isset($value['content'])) {
                $shortcodes[$i]['content'] = $value['content'];
            }
        }

        return $shortcodes;
    }

    private static function parse_attrs($attrs) {
        preg_match_all(self::ATTRIBUTE_REGEXP, $attrs, $matches, PREG_SET_ORDER);
        $attributes = array();
        foreach ($matches as $i => $value) {
            $key = $value['name'];
            $attributes[$i][$key] = $value['value'];
        }
        return $attributes;
    }
}

print_r(Parser::parse_shortcodes('[include file="header.html"]'));

输出:

Array
(
    [0] => Array
        (
            [shortcode] => [include file="header.html"]
            [name] => include
            [attrs] => Array
                (
                    [0] => Array
                        (
                            [file] => header.html
                        )
                )
        )
)

【讨论】:

  • 这很棒..但是有没有办法将它作为替换..它只是转换短代码并删除它周围可能存在的任何其他文本..
  • @REPTILE 该问题要求它将解析短代码并将其作为关联数组输出。然后,您可以获取每个元素并生成您喜欢的任何输出。您可以执行类似str_replace($shortcode, $compiled_shortcode, $string) 的操作,这将搜索短代码,并将其替换为您在字符串中生成的$compiled_output。通常字符串是整个 html,如 post_content
  • 不幸的是当值只有 1 个字符长时不起作用(例如 id=8 或 id="8")。我想我修好了:regex101.com/r/sZ7wP0/6
【解决方案2】:

使用this function

$code = '[include file="header.html"]';
$innerCode = GetBetween($code, '[', ']');
$innerCodeParts = explode(' ', $innerCode);

$command = $innerCodeParts[0];

$attributeAndValue = $innerCodeParts[1];
$attributeParts = explode('=', $attributeAndValue);
$attribute = $attributeParts[0];
$attributeValue = str_replace('"', '', $attributeParts[1]);

echo $command . ' ' . $attribute . '=' . $attributeValue;
//this will result in include file=header.html

$command 将是“包含”

$attribute 将是“文件”

$attributeValue 将是“header.html”

【讨论】:

  • 我可以看到错误:致命错误:在第 4 行的 wp_parse.php 中调用未定义函数 GetBetween()
  • 阅读我回答的第一行,您需要将此代码粘贴到您的文件中:function GetBetween($content,$start,$end){ $r = explode($start, $content); if (isset($r[1])){ $r = explode($end, $r[1]); return $r[0]; } return ''; }
  • @ShahzabAsif 我没有测试我的代码,所以让我知道它是否适合你。
【解决方案3】:

我的 PHP 框架中也需要此功能。这是我写的,效果很好。它适用于我非常喜欢的匿名函数(有点像 JavaScript 中的回调函数)。

<?php
//The content which should be parsed
$content = '<p>Hello, my name is John an my age is [calc-age day="4" month="10" year="1991"].</p>';
$content .= '<p>Hello, my name is Carol an my age is [calc-age day="26" month="11" year="1996"].</p>';

//The array with all the shortcode handlers. This is just a regular associative array with anonymous functions as values. A very cool new feature in PHP, just like callbacks in JavaScript or delegates in C#.
$shortcodes = array(
    "calc-age" => function($data){
        $content = "";
        //Calculate the age
        if(isset($data["day"], $data["month"], $data["year"])){
            $age = date("Y") - $data["year"];
            if(date("m") < $data["month"]){
                $age--;
            }
            if(date("m") == $data["month"] && date("d") < $data["day"]){
                $age--;
            }
            $content = $age;
        }
        return $content;
    }
);
//http://stackoverflow.com/questions/18196159/regex-extract-variables-from-shortcode
function handleShortcodes($content, $shortcodes){
    //Loop through all shortcodes
    foreach($shortcodes as $key => $function){
        $dat = array();
        preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
        if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
            $i = 0;
            $actual_string = $dat[0];
            foreach($dat[1] as $temp){
                $temp = explode(" ", $temp);
                $params = array();
                foreach ($temp as $d){
                    list($opt, $val) = explode("=", $d);
                    $params[$opt] = trim($val, '"');
                }
                $content = str_replace($actual_string[$i], $function($params), $content);
                $i++;
            }
        }
    }
    return $content;
}
echo handleShortcodes($content, $shortcodes);
?>

结果:
你好,我的名字是约翰,我的年龄是 22。
你好,我叫卡罗尔,我今年 17 岁。

【讨论】:

  • 一段很棒的代码 - 谢谢!我确实注意到,如果您将explode like 更改为 $temp = explode('" ', $temp); 那么您可以在引用的值中有空格。
【解决方案4】:

这实际上比表面上看起来更难。安德鲁的回答有效,但如果方括号出现在源文本中[例如,像这样],就会开始崩溃。 WordPress 通过预先注册有效短代码列表来工作,并且仅在括号内的文本与这些预定义值之一匹配时才对括号内的文本进行操作。这样它就不会破坏任何可能恰好有一组方括号的常规文本。

WordPress 短代码引擎的实际 source code 相当健壮,看起来修改文件以使其自行运行并不那么困难 - 然后您可以在您的应用程序中使用它来处理艰巨的工作。 (如果您有兴趣,请查看该文件中的get_shortcode_regex(),看看这个问题的正确解决方案实际上有多麻烦。)

使用 WP shortcodes.php 对您的问题的一个非常粗略的实现看起来像 something

// Define the shortcode
function inlude_shortcode_func($attrs) {
    $data = shortcode_atts(array(
        'file' => 'default'
    ), $attrs);

    return "Including File: {$data['file']}";
}
add_shortcode('include', 'inlude_shortcode_func');

// And then run your page content through the filter
echo do_shortcode('This is a document with [include file="header.html"] included!');

同样,根本没有经过测试,但它不是一个很难使用的 API。

【讨论】:

  • 如果你能包含一个工作示例会更好。
【解决方案5】:

我已经用wordpress函数修改了上面的函数

function extractThis($short_code_string) {
    $shortocode_regexp = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\@\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
    preg_match_all($shortocode_regexp, $short_code_string, $matches, PREG_SET_ORDER);
    $shortcodes = array();
    foreach ($matches as $i => $value) {
       $shortcodes[$i]['shortcode'] = $value['shortcode'];
       $shortcodes[$i]['name'] = $value['name'];
       if (isset($value['attrs'])) {
        $attrs = shortcode_parse_atts($value['attrs']);
        $shortcodes[$i]['attrs'] = $attrs;
       }
       if (isset($value['content'])) {
        $shortcodes[$i]['content'] = $value['content'];
       }
    }
    return $shortcodes;
  }

我认为这对所有人都有帮助:)

【讨论】:

    【解决方案6】:

    更新@Duco 的sn-p,看起来,当我们有类似的东西时,它会被空间破坏

    [Image source="myimage.jpg" alt="My Image"]
    

    到现在的:

    function handleShortcodes($content, $shortcodes){
        function read_attr($attr) {
            $atList = [];
    
            if (preg_match_all('/\s*(?:([a-z0-9-]+)\s*=\s*"([^"]*)")|(?:\s+([a-z0-9-]+)(?=\s*|>|\s+[a..z0-9]+))/i', $attr, $m)) {
                for ($i = 0; $i < count($m[0]); $i++) {
                    if ($m[3][$i])
                        $atList[$m[3][$i]] = null;
                    else
                        $atList[$m[1][$i]] = $m[2][$i];
                }
            }
            return $atList;
        }
        //Loop through all shortcodes
        foreach($shortcodes as $key => $function){
            $dat = array();
            preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
    
            if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){
                $i = 0;
                $actual_string = $dat[0];
                foreach($dat[1] as $temp){
                    $params = read_attr($temp);
                    $content = str_replace($actual_string[$i], $function($params), $content);
                    $i++;
                }
            }
        }
        return $content;
    }
    $content = '[image source="one" alt="one two"]';
    

    结果:

    array( 
      [source] => myimage.jpg,
      [alt] => My Image
    )
    

    更新(2020 年 2 月 11 日)
    它似乎在 preg_match 下遵循正则表达式仅标识具有属性的短代码

    preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);
    

    使其正常使用 [contact-form][mynotes]。我们可以将以下内容更改为

    preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
    

    【讨论】:

      【解决方案7】:

      我也遇到了同样的问题。对于我必须做的事情,我将利用现有的 xml 解析器而不是编写自己的正则表达式。我敢肯定在某些情况下它不起作用

      example.php

      <?php
      
      $file_content = '[include file="header.html"]';
      
      // convert the string into xml
      $xml = str_replace("[", "<", str_replace("]", "/>", $file_content));
      
      $doc = new SimpleXMLElement($xml);
      
      echo "name: " . $doc->getName() . "\n";
      foreach($doc->attributes() as $key => $value) {
          echo "$key: $value\n";
      }
      
      $ php example.php 
      name: include
      file: header.html
      

      要让它在 ubuntu 上运行,我认为你必须这样做

      sudo apt-get install php-xml
      

      (感谢https://drupal.stackexchange.com/a/218271

      如果你在一个文件中有很多这样的字符串,那么我认为你仍然可以进行查找替换,然后将其全部视为 xml。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多