Wordpress在我的短代码中插入开始<p>标签

时间:2015-11-22 00:02:04

标签: php wordpress

我写了一个小函数来在我的首页上显示最新的视频。功能本身工作得很好。唯一的问题是wordpress继续在代码的一个位置插入一个开始<p>标记。 这是我的功能:

function video_start() {
// the query
$the_query = new WP_Query(array('post_type'=>'page','post_parent'=>'17','order'=>'ASC','orderby' => 'date','posts_per_page'=>1));
// The Loop 
if ( $the_query->have_posts() ) 
{
    while ( $the_query->have_posts() ) 
    {
        $the_query->the_post();
        if ( has_post_thumbnail() ) 
        {
            $picid = get_post_thumbnail_id($post_id);
            $alt_text = get_post_meta($picid , '_wp_attachment_image_alt', true);
            $string .= '<div class="featured-start">';
            $string .= '<a href="' . get_the_permalink() .'" class="b-link" rel="bookmark">';
            $string .= '<h2 class="mar-bot">Latest Video</h2>';
            $string .= '<img src="'.wp_get_attachment_url(get_post_thumbnail_id($post_id)).'" class="img-responsive" alt="'.$alt_text.'" />';
            $string .= '<p>'.get_the_title().'</p>';
            $string .= '<div class="orange-button">Watch Video</div></a></div>';
        }
    }
}
else 
{
// no posts found
}
$string .= '<div class="clear"></div>';
return $string;
/* Restore original Post Data */
wp_reset_postdata();
}
// Add a shortcode
add_shortcode('video_startpage', 'video_start');
// Enable shortcodes in text widgets
add_filter('widget_text', 'do_shortcode');

我遇到问题的输出是:

<div class="featured-start">
<a href="http://www.kundenwebseite.inweco.de/videos/pet-project-09-part-1/" class="b-link" rel="bookmark"><br />
<h2 class="mar-bot">Latest Video</h2>
<p><img src="http://www.kundenwebseite.inweco.de/wp-content/uploads/2015/11/pet-project-2009-part-1.jpg" class="img-responsive" alt="" />
<p>Pet Project 09 &#8211; Part 1</p>
<div class="orange-button">Watch Video</div>
<p></a></div>
<div class="clear"></div>

我尝试过几种方法删除wp-autop过滤器,但它根本无法工作。即使使用谷歌超过两个小时后,我也无法找到解决方案。

5 个答案:

答案 0 :(得分:1)

好的。经过长时间的搜索(得到史蒂夫的大量帮助),我终于找到了解决方案。 我从

中获取了wpautop函数(从第456行开始到第604行结束)

https://core.trac.wordpress.org/browser/tags/4.3.1/src/wp-includes/formatting.php#L0

并使用提供的链接中的新qpautop函数替换/ wp-includes /文件夹中的formatting.php文件中的现有wpautop函数。 然后我评论了499行。

所有这一切都让它为我工作。

答案 1 :(得分:1)

这是多年来的一个已知问题。请查看Wordpress Ticket

正如之前提到的其他人一样,有一个插件可以解决这个问题。它被称为&#34; Shortcode Empty Paragraph Fix&#34;。它不是最好的解决方案,但也不是那么糟糕。

我不喜欢在我的wp安装中放入大量的膨胀 - 所以我将短代码包装在没有类的div中并修复了问题。

<div> [woocommerce_cart] </div>

我希望这个问题会在接下来的几年内得到解决;)所以我可以删除我的div - 在我看来是一个更安全的方式,因为有时funcitons.php中的额外功能会导致一些问题。

答案 2 :(得分:0)

wpautop()函数位于wp-includes / formatting.php中,它允许您指定是否需要<p>,但似乎传递参数以将其关闭在您的情况下不起作用 - 这些方法可能有用。

这个使用str_replace()并不是那么糟糕,并提供了其他几个选项:

https://wordpress.org/support/topic/shortcode-is-being-surrounded-by-p-tags

也是同一页面上的一个产品,用于删除自动转换为<p>代码str_replace(array("\n\r", "\n", "\r"), '', $content );

的换行符

这是一个在该页面上提供的插件,但我不知道它是否正常 - 您似乎能够接受所提供的功能并将其添加到您的functions.php - 如果您有一个子主题{ {3}}你可以将它放在functions.php里面,这样当你的父主题更新时它就不会丢失。 (被视为最佳实践)。

https://codex.wordpress.org/Child_Themes

答案 3 :(得分:0)

Wordpress会自动对您的内容应用wpautop过滤器,可以直接在帖子编辑器上添加,也可以通过短代码生成,

避免wordpress在您的内容上添加不需要的标记,

您可以使用块元素包装所有内联元素,而无需向该内联元素添加新行,.e.g

<div><a href="#">Hello</a></div>

将输出<div><a href="#">Hello</a></div>

<div>
    <a href="#">Hello</a>
</div> 

将输出<div><p><a href="#">Hello</a><p></div>

你的选择是;

  1. 将所有新行修剪为您的短代码生成的内容,但这并不是一个好主意,因为您的HTML上没有新行会影响CSS属性
  2. return trim(preg_replace('/\s+/', ' ', $string));

    1. 使用自定义格式化程序覆盖wordpress默认自动格式化程序
    2. 下面这段代码是我主题的内置函数

      
      function my_custom_content_formatter($content) {
          $new_content = '';
          $pattern_full = '{(\[raw\].*?\[/raw\])}is';
          $pattern_contents = '{\[raw\](.*?)\[/raw\]}is';
          $pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);
          foreach ($pieces as $piece) {
              if (preg_match($pattern_contents, $piece, $matches)) {
                  $new_content .= $matches[1];
              } else {
                  $new_content .= wptexturize(wpautop($piece));
              }
          }
      
          return $new_content;
      }
      
      // Remove the 2 main auto-formatters
      remove_filter('the_content', 'wpautop');
      remove_filter('the_content', 'wptexturize');
      
      // apply new auto-formatter
      add_filter('the_content', 'my_custom_content_formatter', 99);
      add_filter('widget_text', 'my_custom_content_formatter', 99);
      

      然后,您可以添加此[raw][video_startpage][/raw]

      之类的短代码

答案 4 :(得分:0)

我遇到了同样的问题,因为上面没有任何真正有用的东西,我决定解决它。所以这是我的解决方案(虽然只适用于具有结束标记的短代码)。

正好我们在同一页面上,拥有 col 的基本短代码,如果我们有这个,则输出具有特定类的div在wp编辑器中:

lorem test
[row]
[col]inside col[/col]
[/row]
dolor

结果输出为:

<p>lorem test<br />
<div class="row "><div class="columns ">inside col</div></div><br />
dolor</p>

这是错误的,正确的方法应该是:

<p>lorem test</p>
<div class="row "><div class="columns ">inside col</div></div>
<p>dolor</p>

为实现这一目标,我们首先将 wpautop 过滤器替换为我们自己的

add_action('init','cod_custom_wpautop',90);
function cod_custom_wpautop() {
   remove_filter('the_content', 'wpautop');
   remove_filter('acf_the_content', 'wpautop');
   add_filter('the_content', 'cod_wpautop');
   add_filter('acf_the_content', 'cod_wpautop');
}

然后实际功能与 wp-includes / formating.php 上的功能基本相同,但是我们自己做了更改:

function cod_wpautop( $pee, $br = true ) {
$pre_tags = array();

if ( trim($pee) === '' )
    return '';

// Just to make things a little easier, pad the end.
$pee = $pee . "\n";

/*
 * Pre tags shouldn't be touched by autop.
 * Replace pre tags with placeholders and bring them back after autop.
 */
if ( strpos($pee, '<pre') !== false ) {
    $pee_parts = explode( '</pre>', $pee );
    $last_pee = array_pop($pee_parts);
    $pee = '';
    $i = 0;

    foreach ( $pee_parts as $pee_part ) {
        $start = strpos($pee_part, '<pre');

        // Malformed html?
        if ( $start === false ) {
            $pee .= $pee_part;
            continue;
        }

        $name = "<pre wp-pre-tag-$i></pre>";
        $pre_tags[$name] = substr( $pee_part, $start ) . '</pre>';

        $pee .= substr( $pee_part, 0, $start ) . $name;
        $i++;
    }

    $pee .= $last_pee;
}
// Change multiple <br>s into two line breaks, which will turn into paragraphs.
$pee = preg_replace('|<br\s*/?>\s*<br\s*/?>|', "\n\n", $pee);

$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';

// Add a double line break above block-level opening tags.
$pee = preg_replace('!(<' . $allblocks . '[\s/>])!', "\n\n$1", $pee);

// Add a double line break below block-level closing tags.
$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);

$shortcode_blocks = '(?:row|col)';
$pee = preg_replace('!(\[' . $shortcode_blocks . '[\s/\]])!', "\n\n$1", $pee);
$pee = preg_replace('!(\[/' . $shortcode_blocks . '\])!', "$1\n\n", $pee);

// Standardize newline characters to "\n".
$pee = str_replace(array("\r\n", "\r"), "\n", $pee);

// Find newlines in all elements and add placeholders.
$pee = wp_replace_in_html_tags( $pee, array( "\n" => " <!-- wpnl --> " ) );

// Collapse line breaks before and after <option> elements so they don't get autop'd.
if ( strpos( $pee, '<option' ) !== false ) {
    $pee = preg_replace( '|\s*<option|', '<option', $pee );
    $pee = preg_replace( '|</option>\s*|', '</option>', $pee );
}

/*
 * Collapse line breaks inside <object> elements, before <param> and <embed> elements
 * so they don't get autop'd.
 */
if ( strpos( $pee, '</object>' ) !== false ) {
    $pee = preg_replace( '|(<object[^>]*>)\s*|', '$1', $pee );
    $pee = preg_replace( '|\s*</object>|', '</object>', $pee );
    $pee = preg_replace( '%\s*(</?(?:param|embed)[^>]*>)\s*%', '$1', $pee );
}

/*
 * Collapse line breaks inside <audio> and <video> elements,
 * before and after <source> and <track> elements.
 */
if ( strpos( $pee, '<source' ) !== false || strpos( $pee, '<track' ) !== false ) {
    $pee = preg_replace( '%([<\[](?:audio|video)[^>\]]*[>\]])\s*%', '$1', $pee );
    $pee = preg_replace( '%\s*([<\[]/(?:audio|video)[>\]])%', '$1', $pee );
    $pee = preg_replace( '%\s*(<(?:source|track)[^>]*>)\s*%', '$1', $pee );
}

// Remove more than two contiguous line breaks.
$pee = preg_replace("/\n\n+/", "\n\n", $pee);

// Split up the contents into an array of strings, separated by double line breaks.
$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);

// Reset $pee prior to rebuilding.
$pee = '';

// Rebuild the content as a string, wrapping every bit with a <p>.
foreach ( $pees as $tinkle ) {
    $pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
}

// Under certain strange conditions it could create a P of entirely whitespace.
$pee = preg_replace('|<p>\s*</p>|', '', $pee);

// Add a closing <p> inside <div>, <address>, or <form> tag if missing.
$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);

// If an opening or closing block element tag is wrapped in a <p>, unwrap it.
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
$pee = preg_replace('!<p>\s*(\[/?' . $shortcode_blocks . '[^\]]*\])\s*</p>!', "$1", $pee);

// In some cases <li> may get wrapped in <p>, fix them.
$pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee);

// If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
$pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);

// If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
$pee = preg_replace('!<p>\s*(\[/?' . $allblocks . '[^\]]*\])!', "$1", $pee);

// If an opening or closing block element tag is followed by a closing <p> tag, remove it.
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
$pee = preg_replace('!(\[/?' . $allblocks . '[^\]]*\])\s*</p>!', "$1", $pee);

// Optionally insert line breaks.
if ( $br ) {
    // Replace newlines that shouldn't be touched with a placeholder.
    $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee);

    // Normalize <br>
    $pee = str_replace( array( '<br>', '<br/>' ), '<br />', $pee );

    // Replace any new line characters that aren't preceded by a <br /> with a <br />.
    $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee);

    // Replace newline placeholders with newlines.
    $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
}

// If a <br /> tag is after an opening or closing block tag, remove it.
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
$pee = preg_replace('!(\[/?' . $shortcode_blocks . '[^\]]*\])\s*<br />!', "$1", $pee);

// If a <br /> tag is before a subset of opening or closing block tags, remove it.
$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
$pee = preg_replace( "|\n</p>$|", '</p>', $pee );

// Replace placeholder <pre> tags with their original content.
if ( !empty($pre_tags) )
    $pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);

// Restore newlines in all elements.
if ( false !== strpos( $pee, '<!-- wpnl -->' ) ) {
    $pee = str_replace( array( ' <!-- wpnl --> ', '<!-- wpnl -->' ), "\n", $pee );
}

return $pee;
}

为了解释一下,我们添加了一个 $ shortcode_blocks ,其功能与 $ allblocks 完全相同,基本上可以将它们识别为块并且不只是一个简单的文字。这样,首先这些标记将包含一个段落标记,稍后将删除。

适合我,所以希望它能为你服务;)