Skip to content

Instantly share code, notes, and snippets.

@mwinckler
Last active February 18, 2017 23:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mwinckler/54595f2ff0dd9313fcee06c99a64822f to your computer and use it in GitHub Desktop.
Save mwinckler/54595f2ff0dd9313fcee06c99a64822f to your computer and use it in GitHub Desktop.
<?php
// Populate this array with your shortcode tag names (not including brackets).
$shortcodes = array( 'contextbox' );
// Leave this array alone; it's what we'll use to stash shortcode content in until wpautop has safely passed.
$shortcode_replacements = array();
// See wp-includes/default-filters.php for core WordPress filter priorities
// 9 comes right before wpautop at 10
add_filter('the_content', 'mw_rescue_shortcodes_from_wpautop', 9);
// Same level as wp_autop, executed after (because ours is added later) but before do_shortcode at 11
add_filter('the_content', 'mw_restore_shortcodes_after_wpautop', 10);
// Returns empty array if no match found, else:
// $result[0] == shortcode_tag_found
// $result[1] == string index
function find_next_shortcode_open_tag( $shortcode, $content, $offset ) {
$matches = array();
$result = preg_match( '/\[' . $shortcode . '( [^]]+)?\]/', $content, $matches, PREG_OFFSET_CAPTURE, $offset );
return $result === 1 ? array( $matches[0][0], $matches[0][1] ) : array();
}
function find_first_shortcode_pos( $content, $offset ) {
global $shortcodes;
$earliest_pos = -1;
$first_shortcode = null;
foreach ( $shortcodes as $shortcode ) {
$result = find_next_shortcode_open_tag( $shortcode, $content, $offset );
if ( count( $result ) === 0 ) {
continue;
}
if ( $earliest_pos == -1 || $result[1] < $earliest_pos ) {
$earliest_pos = $result[1];
$first_shortcode = $shortcode;
}
}
return array( $earliest_pos, $first_shortcode );
}
function mw_rescue_shortcodes_from_wpautop( $content ) {
global $shortcode_replacements;
$opening_index = 0;
while ( $opening_index < strlen( $content ) ) {
$result = find_first_shortcode_pos( $content, $opening_index );
$opening_index = $result[0];
$tag_name = $result[1];
if ( $opening_index == -1 ) {
break;
}
// Found an opening tag? Continue searching until we find the matching closing tag.
// There is the possibility of nested opening tags before reaching the matching close.
$closing_tag = '[/' . $tag_name . ']';
$open_tag_count = 1;
$closing_index = $opening_index;
while ( $open_tag_count > 0 && $closing_index < strlen( $content )) {
$closing_pos = strpos( $content, $closing_tag, $closing_index );
if ( $closing_pos === false ) {
// This is a problem; we have no closing tag. Just take the rest of the content.
$open_tag_count = 0;
$closing_index = strlen( $content );
break;
}
$open_tag_matches = find_next_shortcode_open_tag ( $tag_name, $content, $closing_index );
$open_tag_found = count( $open_tag_matches ) > 0;
if ( $open_tag_found ) {
$matched_open_tag = $open_tag_matches[0];
$next_opening_pos = $open_tag_matches[1];
}
if ( !$open_tag_found || $closing_pos < $next_opening_pos ) {
$closing_index = $closing_pos + strlen( $closing_tag );
$open_tag_count--;
} else {
$closing_index = $next_opening_pos + strlen( $matched_open_tag );
$open_tag_count++;
}
}
// Replace everything from $opening_index to $closing_index with a placeholder and stash that placeholder.
// Don't forget to wrap it in <p> so that wpautop doesn't. :P
do {
$key = '<p>' . md5(rand()) . '</p>';
} while ( array_key_exists( $key, $shortcode_replacements ) );
$shortcode_replacements[$key] = substr( $content, $opening_index, $closing_index - $opening_index );
$content = substr_replace( $content, $key, $opening_index, $closing_index - $opening_index );
$opening_index = $opening_index + strlen( $key );
}
return $content;
}
function mw_restore_shortcodes_after_wpautop( $content ) {
global $shortcode_replacements;
foreach ( $shortcode_replacements as $key => $value ) {
$content = str_replace( $key, $value, $content );
}
return $content;
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment