Create custom [sourcecode] shortcode, the right way?

What I want to do

Sharing code in posts on WordPress is quite a pain with all the HTML escaping to take care of. So, I plan to enclose code in posts within a custom shortcode called [sourcecode], as shown below, and let it automatically escape the special characters.

[sourcecode]
<?php

    // Some code here.

?>
[/sourcecode]

The code

And this is what the relevant function (in my theme’s functions.php) looks like:

/**
 * Functionality to set up custom shortcode correctly.
 *
 * This function is attached to the 'the_content' filter hook.
 */
add_filter( 'the_content', 'run_bbcodes', 7 );
function run_bbcodes( $content ) {
    global $shortcode_tags;

    $orig_shortcode_tags = $shortcode_tags;
    $shortcode_tags = array();

    // New shortcodes below
    add_shortcode( 'sourcecode', 'bbcode_code' );

    $content = do_shortcode( $content );
    $shortcode_tags = $orig_shortcode_tags;

    return $content;
}

/**
 * Add Custom shortcode functions below
 *
 * This function is attached to the 'sourcecode' shortcode hook.
 */
function bbcode_code( $atts, $content = null ) {

    // Ensure contents of a <pre>...</pre> HTML block aren't converted into paragraphs or line-breaks
    $content = clean_pre( $content );

    $content = str_replace(

        // Replace these special characters...
        array( '&', '\0', '<', '>', '\'', '"', "https://wordpress.stackexchange.com/", '[', ']' ),

        // ...with the HTML entities below, respectively
        array( '&amp;', '&#92;&#48;', '&lt;', '&gt;', '&apos;', '&quot;', '&#47;', '&#91;', '&#93;' ),

        $content
    );

    return '<pre><code>' . trim( $content ) . '</code></pre>';
}

/**
 * Related sourcecode worth reading:
 *
 * https://bitbucket.org/cbavota/syntax-highlighter-plugin/src
 *
 * https://github.com/mdawaffe/Highlight.js-for-WordPress/blob/master/highlight-js.php
 *
 * https://github.com/fracek/highlight-wp/blob/master/highlight.php
 *
 * http://plugins.svn.wordpress.org/syntaxhighlighter/trunk/
 *
 * http://blog.webspace.jp/235
 *
 * http://core.trac.wordpress.org/browser/trunk/src/wp-includes/shortcodes.php
 */

Question(s)

Now that the explanation is out of the way…

  1. Am I missing anything else?

    For example, until I read the source of SyntaxHighlighter Evolved plugin, I didn’t know that \0 also needs to be replaced with &#92;&#48; “to work around kses” (which wasn’t clear enough for me).

  2. And other than escaping the special characters, is there anything else that I could possibly be missing? Am I doing it the right way?

    (It would be great if anyone could take a look at this file (PHP source code of SyntaxHighlighter Evolved plugin) and see if you can find something that I need to implement. I already did try my best though.)


PS: Why not use the plugin itself? For one, I don’t want the syntax highlighting that it does; and I want to know if what it does can be implemented easily.

2 s
2

You’re asking about X, but I’ll answer with Y. IMHO, there are too many exceptions to handle to grant another solution.

SyntaxHighlighter Evolved has the following Pro Tip (strong, uppercase, in the original):

TIP: Don’t use the Visual editor if you don’t want your code mangled. TinyMCE will “clean up” your HTML.

Not only that, it’s quite common to have plugins and themes messing around with the_content. Rough (and totally unscientific) measure: 10 occurrences within 50 plugins; 15 occurrences within 50 themes.

Another Pro Tip:

enter image description here

Proposed solution

1) To handle the code, I think it’s either a Custom Field/Box in the Edit Post screen or a bridge between the Post and a “private” Custom Post Type that will store the code. I prefer the latter. Steps:

  • paste the embeddable code into a <textarea> rendered with edit_form_after_title
  • use esc_html to display in the backend
  • and '<pre class="pretty">'.htmlentities($code).</pre> in the frontend

2) To handle the syntax highlight, it’s up to the reader to choose its preferred method. Google Prettify is literally 2 lines of code and adding a class to the <pre> tag. Enqueue the script only when the shortcode is present.

Sample plugin

Custom post type
enter image description here

Post post type
enter image description here

The following is a skeleton and only outlines the logic. And here the links for some goodies:
Working skeleton at Gist
Full plugin at GitHub

<?php
/**
 * Plugin Name: Skeleton for the plugin Snippets Shortcode
 * Plugin URI: https://gist.github.com/brasofilo/6804951
 */

/**
 * Based on Plugin Class Demo
 * https://gist.github.com/toscho/3804204
 */
add_action(
    'plugins_loaded',
    array ( B5F_Snippets_Shortcode::get_instance(), 'plugin_setup' )
);

/**
 * Main class
 *
 * Fires all classes
 * Handles save_post action for other classes
 */
class B5F_Snippets_Shortcode {
    protected static $instance = NULL;
    public $post_type="snippet";    
    public function plugin_setup() {
        new B5F_SS_Cpt();
        new B5F_SS_Posts_Pages_Metabox();
        new B5F_SS_Shortcode();
        add_action( 'save_post', array( $this, '_save_post' ), 10, 2 );
    }
} 

/**
 * Register Snippet post type and render Textarea Field after the Title
 *
 * CPT is hierarchical 
 * Custom Metabox for CPT is left empty, can be used as Language Selector
 * Uses save_post for CPT 
 */
class B5F_SS_Cpt {
    public function __construct() {
        add_action( 'init', array( $this, '_cpt' ) );
        add_action( 'edit_form_after_title', array( $this, 'input_text_area' ) );
    }
}

/**
 * Metabox to select the Snippet and to display the correspondent Shortcode
 *
 * Displayed in Posts and Pages post types
 * Add jQuery to listen to the Snippets Dropdown changes and update the sample Text Field
 * Uses save_post for other Post Types 
 */
class B5F_SS_Posts_Pages_Metabox {
    public function __construct() {
        add_action( 'add_meta_boxes', array( $this, '_meta_boxes' ) );
    }
}

/**
 * Snippets Shortcode
 *
 * First gets the Snippet Post ID, then its associated Meta Data, 
 * finally filters the string with http://php.net/manual/en/function.htmlentities.php 
 *
 * Uses Google Code Prettify
 * https://code.google.com/p/google-code-prettify/
 */
class B5F_SS_Shortcode {
    public function __construct() {
        add_shortcode( 'snippet', array( $this, '_shortcode' ) );
    }
}

Leave a Comment