SyntaxHighlighter. TIP: Don't use the Visual editor if you don't want your code mangled. TinyMCE will "clean up" your HTML. Author: Viper007Bond Author URI: http://www.viper007bond.com/ ************************************************************************** Thanks to: * Alex Gorbatchev for writing the Javascript-powered synatax highlighter script * Andrew Ozz for writing the TinyMCE plugin **************************************************************************/ class SyntaxHighlighter { // All of these variables are private. Filters are provided for things that can be modified. var $pluginver = '3.1.3'; // Plugin version var $agshver = false; // Alex Gorbatchev's SyntaxHighlighter version (dynamically set below due to v2 vs v3) var $shfolder = false; // Controls what subfolder to load SyntaxHighlighter from (v2 or v3) var $settings = array(); // Contains the user's settings var $defaultsettings = array(); // Contains the default settings var $brushes = array(); // Array of aliases => brushes var $shortcodes = array(); // Array of shortcodes to use var $themes = array(); // Array of themes var $usedbrushes = array(); // Stores used brushes so we know what to output var $encoded = false; // Used to mark that a character encode took place var $codeformat = false; // If set, SyntaxHighlighter::get_code_format() will return this value var $content_save_pre_ran = false; // It's possible for the "content_save_pre" filter to run multiple times, so keep track // Initalize the plugin by registering the hooks function __construct() { if ( ! function_exists( 'esc_html' ) ) return; // Load localization domain load_plugin_textdomain( 'syntaxhighlighter', false, '/syntaxhighlighter/localization' ); // Display hooks add_filter( 'the_content', array( &$this, 'parse_shortcodes' ), 7 ); // Posts add_filter( 'comment_text', array( &$this, 'parse_shortcodes_comment' ), 7 ); // Comments add_filter( 'bp_get_the_topic_post_content', array( &$this, 'parse_shortcodes' ), 7 ); // BuddyPress // Into the database add_filter( 'content_save_pre', array( &$this, 'encode_shortcode_contents_slashed_noquickedit' ), 1 ); // Posts add_filter( 'pre_comment_content', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // Comments add_filter( 'group_forum_post_text_before_save', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // BuddyPress add_filter( 'group_forum_topic_text_before_save', array( &$this, 'encode_shortcode_contents_slashed' ), 1 ); // BuddyPress // Out of the database for editing add_filter( 'the_editor_content', array( &$this, 'the_editor_content' ), 1 ); // Posts add_filter( 'comment_edit_pre', array( &$this, 'decode_shortcode_contents' ), 1 ); // Comments add_filter( 'bp_get_the_topic_text', array( &$this, 'decode_shortcode_contents' ), 1 ); // BuddyPress add_filter( 'bp_get_the_topic_post_edit_text', array( &$this, 'decode_shortcode_contents' ), 1 ); // BuddyPress // Outputting SyntaxHighlighter's JS and CSS add_action( 'wp_head', array( &$this, 'output_header_placeholder' ), 15 ); add_action( 'admin_head', array( &$this, 'output_header_placeholder' ), 15 ); // For comments add_action( 'wp_footer', array( &$this, 'maybe_output_scripts' ), 15 ); add_action( 'admin_footer', array( &$this, 'maybe_output_scripts' ), 15 ); // For comments // Admin hooks add_action( 'admin_init', array( &$this, 'register_setting' ) ); add_action( 'admin_menu', array( &$this, 'register_settings_page' ) ); add_action( 'admin_head', array( &$this, 'output_shortcodes_for_tinymce' ) ); add_filter( 'mce_external_plugins', array( &$this, 'add_tinymce_plugin' ) ); add_filter( 'tiny_mce_version', array( &$this, 'break_tinymce_cache' ) ); add_filter( 'save_post', array( &$this, 'mark_as_encoded' ), 10, 2 ); add_filter( 'plugin_action_links', array( &$this, 'settings_link' ), 10, 2 ); // Register widget hooks // Requires change added in WordPress 2.9 if ( class_exists('WP_Embed') ) { add_filter( 'widget_text', array( &$this, 'widget_text_output' ), 7, 2 ); add_filter( 'widget_update_callback', array( &$this, 'widget_text_save' ), 1, 4 ); add_filter( 'widget_form_callback', array( &$this, 'widget_text_form' ), 1, 2 ); } // Create array of default settings (you can use the filter to modify these) $this->defaultsettings = (array) apply_filters( 'syntaxhighlighter_defaultsettings', array( 'theme' => 'default', 'loadallbrushes' => 0, 'shversion' => 3, 'title' => '', 'autolinks' => 1, 'classname' => '', 'collapse' => 0, 'firstline' => 1, 'gutter' => 1, 'htmlscript' => 0, 'light' => 0, 'padlinenumbers' => 'false', 'smarttabs' => 1, 'tabsize' => 4, 'toolbar' => 0, 'wraplines' => 1, // 2.x only ) ); // Create the settings array by merging the user's settings and the defaults $usersettings = (array) get_option('syntaxhighlighter_settings'); $this->settings = wp_parse_args( $usersettings, $this->defaultsettings ); // Dynamically set folder and version names for SynaxHighlighter if ( 2 == $this->settings['shversion'] ) { $this->shfolder = 'syntaxhighlighter2'; $this->agshver = '2.1.364'; } else { $this->shfolder = 'syntaxhighlighter3'; $this->agshver = '3.0.83c'; } // Register brush scripts wp_register_script( 'syntaxhighlighter-core', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shCore.js'), array(), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-as3', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushAS3.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-bash', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushBash.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-coldfusion', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushColdFusion.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-cpp', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCpp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-csharp', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCSharp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-css', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushCss.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-delphi', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushDelphi.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-diff', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushDiff.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-erlang', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushErlang.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-groovy', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushGroovy.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-java', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJava.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-javafx', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJavaFX.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-jscript', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushJScript.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-perl', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPerl.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-php', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPhp.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-plain', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPlain.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-powershell', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPowerShell.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-python', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushPython.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-ruby', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushRuby.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-scala', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushScala.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-sql', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushSql.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-vb', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushVb.js'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_script( 'syntaxhighlighter-brush-xml', plugins_url('syntaxhighlighter/' . $this->shfolder . '/scripts/shBrushXml.js'), array('syntaxhighlighter-core'), $this->agshver ); // Register some popular third-party brushes wp_register_script( 'syntaxhighlighter-brush-clojure', plugins_url('syntaxhighlighter/third-party-brushes/shBrushClojure.js'), array('syntaxhighlighter-core'), '20090602' ); wp_register_script( 'syntaxhighlighter-brush-fsharp', plugins_url('syntaxhighlighter/third-party-brushes/shBrushFSharp.js'), array('syntaxhighlighter-core'), '20091003' ); wp_register_script( 'syntaxhighlighter-brush-latex', plugins_url('syntaxhighlighter/third-party-brushes/shBrushLatex.js'), array('syntaxhighlighter-core'), '20090613' ); wp_register_script( 'syntaxhighlighter-brush-matlabkey', plugins_url('syntaxhighlighter/third-party-brushes/shBrushMatlabKey.js'), array('syntaxhighlighter-core'), '20091209' ); wp_register_script( 'syntaxhighlighter-brush-objc', plugins_url('syntaxhighlighter/third-party-brushes/shBrushObjC.js'), array('syntaxhighlighter-core'), '20091207' ); wp_register_script( 'syntaxhighlighter-brush-r', plugins_url('syntaxhighlighter/third-party-brushes/shBrushR.js'), array('syntaxhighlighter-core'), '20100919' ); // Register theme stylesheets wp_register_style( 'syntaxhighlighter-core', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shCore.css'), array(), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-default', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeDefault.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-django', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeDjango.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-eclipse', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeEclipse.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-emacs', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeEmacs.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-fadetogrey', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeFadeToGrey.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-midnight', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeMidnight.css'), array('syntaxhighlighter-core'), $this->agshver ); wp_register_style( 'syntaxhighlighter-theme-rdark', plugins_url('syntaxhighlighter/' . $this->shfolder . '/styles/shThemeRDark.css'), array('syntaxhighlighter-core'), $this->agshver ); // Create list of brush aliases and map them to their real brushes // The key is the language alias // The value is the script handle suffix: syntaxhighlighter-brush-ThisBitHere (your plugin needs to register the script itself) $this->brushes = (array) apply_filters( 'syntaxhighlighter_brushes', array( 'as3' => 'as3', 'actionscript3' => 'as3', 'bash' => 'bash', 'shell' => 'bash', 'coldfusion' => 'coldfusion', 'cf' => 'coldfusion', 'clojure' => 'clojure', 'clj' => 'clojure', 'cpp' => 'cpp', 'c' => 'cpp', 'c-sharp' => 'csharp', 'csharp' => 'csharp', 'css' => 'css', 'delphi' => 'delphi', 'pas' => 'delphi', 'pascal' => 'delphi', 'diff' => 'diff', 'patch' => 'diff', 'erl' => 'erlang', 'erlang' => 'erlang', 'fsharp' => 'fsharp', 'groovy' => 'groovy', 'java' => 'java', 'jfx' => 'javafx', 'javafx' => 'javafx', 'js' => 'jscript', 'jscript' => 'jscript', 'javascript' => 'jscript', 'latex' => 'latex', // Not used as a shortcode 'tex' => 'latex', 'matlab' => 'matlabkey', 'objc' => 'objc', 'obj-c' => 'objc', 'perl' => 'perl', 'pl' => 'perl', 'php' => 'php', 'plain' => 'plain', 'text' => 'plain', 'ps' => 'powershell', 'powershell' => 'powershell', 'py' => 'python', 'python' => 'python', 'r' => 'r', // Not used as a shortcode 'splus' => 'r', 'rails' => 'ruby', 'rb' => 'ruby', 'ror' => 'ruby', 'ruby' => 'ruby', 'scala' => 'scala', 'sql' => 'sql', 'vb' => 'vb', 'vbnet' => 'vb', 'xml' => 'xml', 'xhtml' => 'xml', 'xslt' => 'xml', 'html' => 'xml', 'xhtml' => 'xml', ) ); // Create a list of shortcodes to use. You can use the filter to add/remove ones. // If the language/lang parameter is left out, it's assumed the shortcode name is the language. // If that's invalid, then "plain" is used. $this->shortcodes = array( 'sourcecode', 'source', 'code' ); $this->shortcodes = array_merge( $this->shortcodes, array_keys( $this->brushes ) ); // Remove some shortcodes we don't want while still supporting them as language values unset( $this->shortcodes[array_search( 'latex', $this->shortcodes )] ); // Remove "latex" shortcode (it'll collide) unset( $this->shortcodes[array_search( 'r', $this->shortcodes )] ); // Remove "r" shortcode (too short) $this->shortcodes = (array) apply_filters( 'syntaxhighlighter_shortcodes', $this->shortcodes ); // Register each shortcode with a placeholder callback so that strip_shortcodes() will work // The proper callback and such is done in SyntaxHighlighter::shortcode_hack() foreach ( $this->shortcodes as $shortcode ) add_shortcode( $shortcode, '__return_true' ); // Create list of themes and their human readable names // Plugins can add to this list: http://www.viper007bond.com/wordpress-plugins/syntaxhighlighter/adding-a-new-theme/ $this->themes = (array) apply_filters( 'syntaxhighlighter_themes', array( 'default' => __( 'Default', 'syntaxhighlighter' ), 'django' => __( 'Django', 'syntaxhighlighter' ), 'eclipse' => __( 'Eclipse', 'syntaxhighlighter' ), 'emacs' => __( 'Emacs', 'syntaxhighlighter' ), 'fadetogrey' => __( 'Fade to Grey', 'syntaxhighlighter' ), 'midnight' => __( 'Midnight', 'syntaxhighlighter' ), 'rdark' => __( 'RDark', 'syntaxhighlighter' ), 'none' => __( '[None]', 'syntaxhighlighter' ), ) ); // Other special characters that need to be encoded before going into the database (namely to work around kses) $this->specialchars = (array) apply_filters( 'syntaxhighlighter_specialchars', array( '\0' => '\0', ) ); } // Register the settings page function register_settings_page() { add_options_page( __( 'SyntaxHighlighter Settings', 'syntaxhighlighter' ), __( 'SyntaxHighlighter', 'syntaxhighlighter' ), 'manage_options', 'syntaxhighlighter', array( &$this, 'settings_page' ) ); } // Register the plugin's setting function register_setting() { register_setting( 'syntaxhighlighter_settings', 'syntaxhighlighter_settings', array( &$this, 'validate_settings' ) ); } // Add the custom TinyMCE plugin which wraps plugin shortcodes in
in TinyMCE
function add_tinymce_plugin( $plugins ) {
$plugins['syntaxhighlighter'] = plugins_url('syntaxhighlighter/syntaxhighlighter_mce.js');
return $plugins;
}
// Break the TinyMCE cache
function break_tinymce_cache( $version ) {
return $version . '-sh' . $this->pluginver;
}
// Add a "Settings" link to the plugins page
function settings_link( $links, $file ) {
static $this_plugin;
if( empty($this_plugin) )
$this_plugin = plugin_basename(__FILE__);
if ( $file == $this_plugin )
$links[] = '' . __( 'Settings', 'syntaxhighlighter' ) . '';
return $links;
}
// Output list of shortcode tags for the TinyMCE plugin
function output_shortcodes_for_tinymce() {
$shortcodes = array();
foreach ( $this->shortcodes as $shortcode )
$shortcodes[] = preg_quote( $shortcode );
echo "\n";
}
// Additional CSS for the front end (to ensure themes don't screw too much with the code)
function enforce_font_size() {
echo ' ' . "\n";
}
// A filter function that runs do_shortcode() but only with this plugin's shortcodes
function shortcode_hack( $content, $callback ) {
global $shortcode_tags;
// Backup current registered shortcodes and clear them all out
$orig_shortcode_tags = $shortcode_tags;
remove_all_shortcodes();
// Register all of this plugin's shortcodes
foreach ( $this->shortcodes as $shortcode )
add_shortcode( $shortcode, $callback );
// Do the shortcodes (only this plugins's are registered)
$content = $this->do_shortcode_keep_escaped_tags( $content );
// Put the original shortcodes back
$shortcode_tags = $orig_shortcode_tags;
return $content;
}
// This is a clone of do_shortcode() that uses a different callback function
// The new callback function will keep escaped tags escaped, i.e. [[foo]]
// Up to date as of r18324 (3.2)
function do_shortcode_keep_escaped_tags( $content ) {
global $shortcode_tags;
if (empty($shortcode_tags) || !is_array($shortcode_tags))
return $content;
$pattern = get_shortcode_regex();
return preg_replace_callback('/'.$pattern.'/s', array( &$this, 'do_shortcode_tag_keep_escaped_tags' ), $content);
}
// Callback for above do_shortcode_keep_escaped_tags() function
// It's a clone of core's do_shortcode_tag() function with a modification to the escaped shortcode return
// Up to date as of r18324 (3.2)
function do_shortcode_tag_keep_escaped_tags( $m ) {
global $shortcode_tags;
// allow [[foo]] syntax for escaping a tag
if ( $m[1] == '[' && $m[6] == ']' ) {
return $m[0]; // This line was modified for this plugin (no substr call)
}
$tag = $m[2];
$attr = shortcode_parse_atts( $m[3] );
if ( isset( $m[5] ) ) {
// enclosing tag - extra parameter
return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, $m[5], $tag ) . $m[6];
} else {
// self-closing tag
return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, NULL, $tag ) . $m[6];
}
}
// The main filter for the post contents. The regular shortcode filter can't be used as it's post-wpautop().
function parse_shortcodes( $content ) {
return $this->shortcode_hack( $content, array( &$this, 'shortcode_callback' ) );
}
// HTML entity encode the contents of shortcodes
function encode_shortcode_contents( $content ) {
return $this->shortcode_hack( $content, array( &$this, 'encode_shortcode_contents_callback' ) );
}
// HTML entity encode the contents of shortcodes. Expects slashed content.
function encode_shortcode_contents_slashed( $content ) {
return addslashes( $this->encode_shortcode_contents( stripslashes( $content ) ) );
}
// HTML entity encode the contents of shortcodes. Expects slashed content. Aborts if AJAX.
function encode_shortcode_contents_slashed_noquickedit( $content ) {
// In certain weird circumstances, the content gets run through "content_save_pre" twice
// Keep track and don't allow this filter to be run twice
// I couldn't easily figure out why this happens and didn't bother looking into it further as this works fine
if ( true == $this->content_save_pre_ran )
return $content;
$this->content_save_pre_ran = true;
// Post quick edits aren't decoded for display, so we don't need to encode them (again)
if ( !empty($_POST) && !empty($_POST['action']) && 'inline-save' == $_POST['action'] )
return $content;
return $this->encode_shortcode_contents_slashed( $content );
}
// HTML entity decode the contents of shortcodes
function decode_shortcode_contents( $content ) {
return $this->shortcode_hack( $content, array( &$this, 'decode_shortcode_contents_callback' ) );
}
// The callback function for SyntaxHighlighter::encode_shortcode_contents()
function encode_shortcode_contents_callback( $atts, $code = '', $tag = false ) {
$this->encoded = true;
$code = str_replace( array_keys($this->specialchars), array_values($this->specialchars), htmlspecialchars( $code ) );
return '[' . $tag . $this->atts2string( $atts ) . "]{$code}[/$tag]";
}
// The callback function for SyntaxHighlighter::decode_shortcode_contents()
// Shortcode attribute values need to not be quoted with TinyMCE disabled for some reason (weird bug)
function decode_shortcode_contents_callback( $atts, $code = '', $tag = false ) {
$quotes = ( user_can_richedit() ) ? true : false;
$code = str_replace( array_values($this->specialchars), array_keys($this->specialchars), htmlspecialchars_decode( $code ) );
return '[' . $tag . $this->atts2string( $atts, $quotes ) . "]{$code}[/$tag]";
}
// Dynamically format the post content for the edit form
function the_editor_content( $content ) {
global $post;
// New code format (stored encoded in database)
if ( 2 == $this->get_code_format( $post ) ) {
// If TinyMCE is disabled or the HTML tab is set to be displayed first, we need to decode the HTML
if ( !user_can_richedit() || 'html' == wp_default_editor() )
$content = $this->decode_shortcode_contents( $content );
}
// Old code format (stored raw in database)
else {
// If TinyMCE is enabled and is set to be displayed first, we need to encode the HTML
if ( user_can_richedit() && 'html' != wp_default_editor() )
$content = $this->encode_shortcode_contents( $content );
}
return $content;
}
// Run SyntaxHighlighter::encode_shortcode_contents() on the contents of the text widget
function widget_text_save( $instance, $new_instance, $old_instance, $widgetclass ) {
if ( 'text' == $widgetclass->id_base ) {
// Re-save the widget settings but this time with the shortcode contents encoded
$new_instance['text'] = $this->encode_shortcode_contents( $new_instance['text'] );
$instance = $widgetclass->update( $new_instance, $old_instance );
// And flag it as encoded
$instance['syntaxhighlighter_encoded'] = true;
}
return $instance;
}
// Run SyntaxHighlighter::decode_shortcode_contents_callback() on the contents of the text widget form
function widget_text_form( $instance, $widgetclass ) {
if ( 'text' == $widgetclass->id_base && !empty($instance['syntaxhighlighter_encoded']) ) {
$instance['text'] = $this->shortcode_hack( $instance['text'], array( &$this, 'decode_shortcode_contents_callback' ) );
}
return $instance;
}
// Run SyntaxHighlighter::parse_shortcodes() on the contents of a text widget
function widget_text_output( $content, $instance = false ) {
$this->codeformat = ( false === $instance || empty($instance['syntaxhighlighter_encoded']) ) ? 1 : 2;
$content = $this->parse_shortcodes( $content );
$this->codeformat = false;
return $content;
}
// Run SyntaxHighlighter::parse_shortcodes() on the contents of a comment
function parse_shortcodes_comment( $content ) {
$this->codeformat = 2;
$content = $this->parse_shortcodes( $content );
$this->codeformat = false;
return $content;
}
// This function determines what version of SyntaxHighlighter was used when the post was written
// This is because the code was stored differently for different versions of SyntaxHighlighter
function get_code_format( $post ) {
if ( false !== $this->codeformat )
return $this->codeformat;
if ( empty($post) )
$post = new stdClass();
if ( null !== $version = apply_filters( 'syntaxhighlighter_pre_getcodeformat', null, $post ) )
return $version;
$version = ( empty($post->ID) || get_post_meta( $post->ID, '_syntaxhighlighter_encoded', true ) || get_post_meta( $post->ID, 'syntaxhighlighter_encoded', true ) ) ? 2 : 1;
return apply_filters( 'syntaxhighlighter_getcodeformat', $version, $post );
}
// Adds a post meta saying that HTML entities are encoded (for backwards compatibility)
function mark_as_encoded( $post_ID, $post ) {
if ( false == $this->encoded || 'revision' == $post->post_type )
return;
delete_post_meta( $post_ID, 'syntaxhighlighter_encoded' ); // Previously used
add_post_meta( $post_ID, '_syntaxhighlighter_encoded', true, true );
}
// Transforms an attributes array into a 'key="value"' format (i.e. reverses the process)
function atts2string( $atts, $quotes = true ) {
if ( empty($atts) )
return '';
$atts = $this->attributefix( $atts );
// Re-map [code="php"] style tags
if ( isset($atts[0]) ) {
if ( empty($atts['language']) )
$atts['language'] = $atts[0];
unset($atts[0]);
}
$strings = array();
foreach ( $atts as $key => $value )
$strings[] = ( $quotes ) ? $key . '="' . esc_attr( $value ) . '"' : $key . '=' . esc_attr( $value );
return ' ' . implode( ' ', $strings );
}
// Simple function for escaping just single quotes (the original js_escape() escapes more than we need)
function js_escape_singlequotes( $string ) {
return str_replace( "'", "\'", $string );
}
// Output an anchor in the header for the Javascript to use
// Might as well use it to output the version to help me debug people's sites
function output_header_placeholder() {
echo '' . "\n";
}
// Output any needed scripts. This is meant for the footer.
function maybe_output_scripts() {
global $wp_styles;
if ( 1 == $this->settings['loadallbrushes'] )
$this->usedbrushes = array_flip( array_values( $this->brushes ) );
if ( empty($this->usedbrushes) )
return;
$scripts = array();
foreach ( $this->usedbrushes as $brush => $unused )
$scripts[] = 'syntaxhighlighter-brush-' . strtolower( $brush );
wp_print_scripts( $scripts );
// Stylesheets can't be in the footer, so inject them via Javascript
echo "
's
function shortcode_callback( $atts, $code = '', $tag = false ) {
global $post;
if ( false === $tag || empty($code) )
return $code;
// Avoid PHP notices
if ( !isset($post) )
$post = null;
$code = apply_filters( 'syntaxhighlighter_precode', $code, $atts, $tag );
// Error fixing for [tag="language"]
if ( isset($atts[0]) ) {
$atts = $this->attributefix( $atts );
$atts['language'] = $atts[0];
unset($atts[0]);
}
// Default out all of the available parameters to "false" (easy way to check if they're set or not)
// Note this isn't the same as if the user passes the string "false" to the shortcode
$atts = (array) apply_filters( 'syntaxhighlighter_shortcodeatts', shortcode_atts( array(
'language' => false,
'lang' => false,
'type' => false, // language alias
'autolinks' => false,
'classname' => false,
'collapse' => false,
'firstline' => false,
'fontsize' => false,
'gutter' => false,
'highlight' => false,
'htmlscript' => false,
'light' => false,
'padlinenumbers' => false,
'smarttabs' => false,
'tabsize' => false,
'title' => $this->settings['title'],
'toolbar' => false,
'wraplines' => false,
), $atts ) );
// Check for language shortcode tag such as [php]code[/php]
if ( isset($this->brushes[$tag]) ) {
$lang = $tag;
}
// If a valid tag is not used, it must be sourcecode/source/code
else {
$atts = $this->attributefix( $atts );
// Check for the "language" attribute
if ( false !== $atts['language'] )
$lang = $atts['language'];
// Check for the "lang" attribute
elseif ( false !== $atts['lang'] )
$lang = $atts['lang'];
// Default to plain text
else
$lang = 'text';
// All language aliases are lowercase
$lang = strtolower( $lang );
// Validate passed attribute
if ( !isset($this->brushes[$lang]) )
return $code;
}
// Switch from the alias to the real brush name (so custom aliases can be used)
$lang = $this->brushes[$lang];
// Register this brush as used so it's script will be outputted
$this->usedbrushes[$lang] = true;
$params = array();
$params[] = "brush: $lang;";
// Fix bug that prevents collapse from working if the toolbar is off or light mode is on
if ( 'true' == $atts['collapse'] || '1' === $atts['collapse'] || 1 == $this->settings['collapse'] ) {
$atts['toolbar'] = 'true';
$atts['light'] = 'false';
}
// Parameter renaming (the shortcode API doesn't like parameter names with dashes)
$rename_map = array(
'autolinks' => 'auto-links',
'classname' => 'class-name',
'firstline' => 'first-line',
'fontsize' => 'font-size',
'htmlscript' => 'html-script',
'padlinenumbers' => 'pad-line-numbers',
'smarttabs' => 'smart-tabs',
'tabsize' => 'tab-size',
'wraplines' => 'wrap-lines',
);
// Allowed configuration parameters and their type
// Use the proper names (see above)
$allowed_atts = (array) apply_filters( 'syntaxhighlighter_allowedatts', array(
'auto-links' => 'boolean',
'class-name' => 'other',
'collapse' => 'boolean',
'first-line' => 'integer',
'font-size' => 'integer',
'gutter' => 'boolean',
'highlight' => 'other',
'html-script' => 'boolean',
'light' => 'boolean',
'pad-line-numbers' => 'other',
'smart-tabs' => 'boolean',
'tab-size' => 'integer',
'title' => 'other',
'toolbar' => 'boolean',
'wrap-lines' => 'boolean',
) );
$title = '';
// Sanitize configuration parameters and such
foreach ( $atts as $key => $value ) {
$key = strtolower( $key );
// Put back parameter names that have been renamed for shortcode use
if ( !empty($rename_map[$key]) )
$key = $rename_map[$key];
// This this parameter if it's unknown, not set, or the language which was already handled
if ( empty($allowed_atts[$key]) || false === $value || in_array( $key, array( 'language', 'lang' ) ) )
continue;
// Sanitize values
switch ( $allowed_atts[$key] ) {
case 'boolean':
$value = strtolower( $value );
if ( 'true' === $value || '1' === $value || 'on' == $value )
$value = 'true';
elseif ( 'false' === $value || '0' === $value || 'off' == $value )
$value = 'false';
else
continue 2; // Invalid value, ditch parameter
break;
// integer
case 'integer':
$value = (int) $value;
break;
}
// Sanitize the "classname" parameter
if ( 'classname' == $key )
$value = trim( preg_replace( '/[^a-zA-Z0-9 _-]/i', '', $value ) );
// Special sanitization for "pad-line-numbers"
if ( 'pad-line-numbers' == $key ) {
$value = strtolower( $value );
if ( 'true' === $value || '1' === $value )
$value = 'true';
elseif ( 'false' === $value || '0' === $value )
$value = 'false';
else
$value = (int) $value;
}
// Add % sign to "font-size"
if ( 'font-size' == $key )
$value = $value . '%';
// If "html-script", then include the XML brush as it's needed
if ( 'html-script' == $key && 'true' == $value )
$this->usedbrushes['xml'] = true;
// Sanitize row highlights
if ( 'highlight' == $key ) {
if ( false === strpos( $value, ',' ) ) {
$value = (int) $value;
} else {
$lines = explode( ',', $value );
$highlights = array();
foreach ( $lines as $line ) {
// Line range
if ( false !== strpos( $line, '-' ) ) {
list( $range_start, $range_end ) = array_map( 'intval', explode( '-', $line ) );
if ( ! $range_start || ! $range_end || $range_end <= $range_start )
continue;
for ( $i = $range_start; $i <= $range_end; $i++ )
$highlights[] = $i;
} else {
$highlights[] = (int) $line;
}
}
natsort( $highlights );
$value = implode( ',', $highlights );
}
if ( empty( $value ) )
continue;
// Wrap highlight in [ ]
$params[] = "$key: [$value];";
continue;
}
$params[] = "$key: $value;";
// Set the title variable if the title parameter is set (but not for feeds)
if ( 'title' == $key && ! is_feed() )
$title = ' title="' . esc_attr( $value ) . '"';
}
$code = ( false === strpos( $code, '<' ) && false === strpos( $code, '>' ) && 2 == $this->get_code_format($post) ) ? strip_tags( $code ) : htmlspecialchars( $code );
$params[] = 'notranslate'; // For Google, see http://otto42.com/9k
$params = apply_filters( 'syntaxhighlighter_cssclasses', $params ); // Use this to add additional CSS classes / SH parameters
return apply_filters( 'syntaxhighlighter_htmlresult', '' . $code . '
' );;
}
// Settings page
function settings_page() { ?>
';
$title = ( empty( $this->settings['title'] ) && 1 != $this->settings['collapse'] ) ? ' title="Code example: (this example was added using the title parameter)"' : '';
// Site owners may opt to disable the short tags, i.e. [php]
$democode = apply_filters( 'syntaxhighlighter_democode', '[sourcecode language="php" htmlscript="true" highlight="12"' . $title . ']
PHP Code Example
' . __( 'PHP Code Example', 'syntaxhighlighter' ) . '
' . __( 'This line is highlighted.', 'syntaxhighlighter' ) . '
[/sourcecode]' );
$this->codeformat = 1;
echo $this->parse_shortcodes( $democode );
$this->codeformat = false;
echo '';
?>
true', '1', 'false', '0' ); ?>
lang', 'language', 'http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes' ); ?>2,5-10,12' ); ?>true (automatic padding), or an integer (forced padding).', 'padlinenumbers parameter', 'syntaxhighlighter' ), 'padlinenumbers' ); ?>collapse' ); ?>[php][/php][css autolinks="false" classname="myclass" collapse="false" firstline="1" gutter="true" highlight="1-3,6,9" htmlscript="false" light="false" padlinenumbers="false" smarttabs="true" tabsize="4" toolbar="true" title=""][/css][code lang="js"][/code][sourcecode language="plain"][/sourcecode]