Shortcode from a widget is wrapped in unwanted <p> element

I’m using Black Studio TinyMCE Widget as a rich text editor widget. In a sidebar I inserted the TinyMCE widget with a [testimonial] shortcode and some content after it.

For example:

Read More
[testimonial]

Read more client testimonials (as a link)

When I switch to the HTML tab of that widget I’ve got the following:

<p>[testimonial]</p>
<p><a title="Testimonials" href="http://mm.dev/testimonials/">Read more client testimonials</a></p>

The shorcode simply displaying a random Testimonial CPT post:

add_shortcode("testimonial", "dlma_testimonial_shortcode");
function dlma_testimonial_shortcode($atts, $content = null){
    $args = array(
        'post_type' => 'testimonial',
        'post_status' => 'publish',
        'posts_per_page' => '1',
        'orderby' => 'rand'
    );
    $testimonial = new WP_Query($args);

    if($testimonial){
        return apply_filters('the_content', $testimonial->posts[0]->post_content);
    }
    return "";
}

However, when I view a page, stray <p> elements are inserted:
Edited thanks to Tom J Nowell

<div class="textwidget">
  <p>
    <blockquote>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vestibulum velit convallis sem pulvinar vitae lobortis metus varius.รขย€ย <em>Person name, Person job</em></p>
    </blockquote>
  </p>
  <p>
    <a href="http://mysite.com/testimonials/" title="Testimonials">Read more client testimonials</a>
  </p>
</div>

The [testimonial] shortcode got expanded correctly, however, as it was originally wrapped into <p> element in the widget it still appears to be wrapped in it. I have tried deleting the <p> element from the widget HTML tab view, however, whenever the Save button is clicked the <p> element is inserted again.

I’ve tried to remove unwanted <p> element that wraps the shortcode with the the_content filter as following:

remove_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'wpautop' , 12);

That didn’t work. I’m guessing I’ve got the flow wrong of processing the content of a widget with a shortcode in it. I’m very confused now. How can I remove unwanted <p> elements that wrap shortcodes?

I would hugely appreciate any help!

Many thanks.

Related posts

Leave a Reply

5 comments

  1. There actually are several ways to handle the WordPress editor wrapping shortcodes in <p> tags.

    This code shows probably the simplest way to do it…just a simple and short function you need to drop into your functions.php file. Once you do, no more tags around your shortcodes that are on their own line!

    function wpex_clean_shortcodes($content){   
    $array = array (
        '<p>[' => '[', 
        ']</p>' => ']', 
        ']<br />' => ']'
    );
    $content = strtr($content, $array);
    return $content;
    }
    add_filter('the_content', 'wpex_clean_shortcodes');
    

    Source: http://www.wpexplorer.com/snippet/clean-wordpress-shortcodes

    Hope that helps someone!

  2. This is a known issue since years. Please have a look at WordPress Ticket.

    As others maybe mentioned before, there is Plugin to fix this issue. It is called “Shortcode Empty Paragraph Fix“. Its not the best solution but not so bad.

    Im not a fan of putting a lot of bloat to my wp installation – so i wrapped the shortcode in div without a class and fixed the problem.

    <div> [woocommerce_cart] </div>
    

    I hope the issue will adressed in the next few years ๐Ÿ˜‰ so i can remove my divs – in my opinion a saver way, because sometimes extra functions in the funcitons.php can cause some problems down the road.

  3. A blockquote is a block element, and shouldn’t be put inside a <p> tag, what you’re seeing is your browsers DOM trying to compensate for the invalid html markup. If you look at the raw source code itself generated, you will not find those stray paragraph tags

    Remove your <p> wrapping tags, and make sure any content that needs wrapping in a <p> tag is done inside the shortcode.

    https://stackoverflow.com/questions/3428828/p-tag-is-a-block-level-element-in-xhtml

    The general rule is that a <p> element is a block element, but it should never contain block elements, only inline elements.

    e.g.:

    • A p element can contain:
      • span
      • b
      • strong
      • etc
    • A p element cannot contain:
      • div
      • blockquote
      • ul
      • ol
      • h1
      • etc
  4. I would suggest this, which moves specific ‘block-level’ shortcodes outside of ‘p’ elements without affecting those elsewhere that may be intended to be inline:

    function my_fix_shortcodes($content){  
      if (strpos($content, '<p>') !== false) {
        /* Move 'block level' shortcode tags outside <p> elements by surrounding with </p>...<p>
           If they have content, this will be put inside a new <p>
           - you could use a final regex to remove this if needed... */
        $block_level_shortcodes = array(
          'testimonial',
          'another_shortcode'
        );
        $regex_shortcode = '(' . implode('|', $block_level_shortcodes) . ')';
        // Match opening/standalone or closing shortcode tags
        $regex = '/([' . $regex_shortcode . '[^]]*]|[/' . $regex_shortcode . '])/';
        $regex_count = 0;
        $content = preg_replace($regex, '</p>$1<p>', $content, -1, $regex_count);
        if ($regex_count > 0) {
          /* Remove <br/>s at start or end of <p> which might now be present,
             then any empty <p>s which quite probably are */
          $content = preg_replace(
            array('/<p>s*<br */>/s', '/<br */>s*</p>/s', '/<p>s*</p>/s'),
            array('<p>', '</p>', ''),
            $content
          );                    
        }
      }
      return $content;
    }
    add_filter('the_content', 'my_fix_shortcodes');
    

    Also note that there seems to be a failed attempt to resolve this sort of issue within WordPress [4.00] itself, so your shortcode handlers may be passed $content that is prepended with </p> and postfixed with <p>, which you will have to detect and remove.

    Update: there seems to be something broken within WordPress itself (relating to sporadic addition of <p> and </p>, outside of the straightforward initial wpautop, when shortcodes are involved, as alluded to above [but those sporadic elements are not passed to your handler]) which means this solution may not always work, even though it should :/

  5. Maybe this can help you (or others too):

    // remove <br> tags from text widget content, from 4.8 version WP adds these tags
    remove_filter('widget_text_content', 'wpautop');