Paulund

Remove Automatic Paragraphs In Shortcodes

This post is an extension to the post I wrote some time ago about displaying code snippets on a WordPress site. This post showed how you can create a WordPress plugin which makes a shortcode for a number of different languages which will encode the content so that you can display code snippets on your WordPress site. Using this plugin you will have access to 4 shortcodes html, css, javascript and php.

<div class="html">
     <h1>HTML</h1>
</div>


.css_class
{

}


var js = document.getElementById('element');


<?php
     echo 'This is PHP.';
?>

But because we were encoding the content using htmlentities it caused some problems with the way WordPress renders content. WordPress will automatically change double line breaks to paragraph tags. In this article we will see what those problems are and come up with a solution to solve them.

WordPress Automatic Paragraphs

When WordPress displays your content on the page it will run it through a number of different filters wptexturize and wpautop. wptexturize is a filter that will convert all quotes into smart quotes, it will also convert apostrophes, dashes, ellipses, the trademark symbol, and the multiplication symbol. Because code normally uses straight quotes instead of curly quotes text inside pre and code tags are ignored. wpautop is a filter that will change double line breaks into paragragh tags. When uses tinyMCE editor and you add a new line it will create a double line break so this filter solves this problem. This is a problem inside shortcodes that are running the content through the htmlentities() function because it will convert the html so it is shown in the shortcode content area. Therefore if you create a shortcode to display HTML like this:


[ html ]
<div id="code"></div>
[ /html ]

Because we have line breaks in this shortcode by going to a new line wpautop() will try to convert this text, plus we are using htmlentities on the content of shortcode the output will actually display these paragraph tags and line break tags. What will actually be returned from the shortcode is this.


</p>
<div id="code"></div><br/>
<p>

You can see the closing paragraph tag and the line break at the end of the line with the div. If you are trying to display more information such as a CSS class with line break on each property it will be displayed as this.


<br />
.alert-danger,<;br />
.alert-error {<br />
color: #b94a48;<br />
background-color: #f2dede;<br />
border-color: #eed3d7;<br />
}<br />

Turning Off wpautop()

Remove these line breaks and paragraph tags from the content is very easily done in WordPress all we have to do is make sure the content doesn't go through the wpautop filter by removing it. To remove a filter in WordPress all you have to do is use the function remove_filter() and pass in the tag of the_content and removing the function wpautop.


remove_filter('the_content', 'wpautop');

But if we use this function to remove the wpautop() then it will be removed for all content which will remove all paragraphs in your content, which makes your content unreadable. In order to display code snippets correctly we need to find out a way of solving this problem without turning off wpautop() on all content, we will only want to turn this off on content inside shortcodes. ## Removing wpautop() To Content Only In Shortcodes

To remove the automatic paragraphs only in shortcodes we need to use an inbuilt function for WordPress called shortcode_unautop() which will remove all the auto formatting in your shortcodes.


/**
 * Don't auto-p wrap shortcodes that stand alone
 *
 * Ensures that shortcodes are not wrapped in <<p>>...<</p>>.
 *
 * @since 2.9.0
 *
 * @param string $content The content.
 * @return string The filtered content.
 */
function shortcode_unautop( $content ) {
	global $shortcode_tags;

	if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
		return $content;
	}

	$tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );

	$pattern =
		  '/'
		. '<p>'                              // Opening paragraph
		. '\\s*+'                            // Optional leading whitespace
		. '('                                // 1: The shortcode
		.     '\\['                          // Opening bracket
		.     "($tagregexp)"                 // 2: Shortcode name
		.     '(?![\\w-])'                   // Not followed by word character or hyphen
		                                     // 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
		.     ')*?'
		.     '(?:'
		.         '\\/\\]'                   // Self closing tag and closing bracket
		.     '|'
		.         '\\]'                      // Closing bracket
		.         '(?:'                      // 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
		.         ')?'
		.     ')'
		. ')'
		. '\\s*+'                            // optional trailing whitespace
		. '<\\/p>'                           // closing paragraph
		. '/s';

	return preg_replace( $pattern, '$1', $content );
}

All we have to do is apply this filter after the content has gone through the wpautop() function, to do this all we have to do is change the order of when these filters work by using the following code.


remove_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'wpautop' , 99);
add_filter( 'the_content', 'shortcode_unautop',100 );

We first remove the wpautop() function and then re-add it with a different priority, now we can apply the shortcode_unautop() after the wpautop() function. Now all the code inside of the shortcodes will not have a trailing paragraph tag and you will no longer have line breaks at the end of your code snippets. To get a copy of the syntax highlighter used on Paulund it is available on github as a WordPress plugin.